2 Replies Latest reply on Mar 2, 2006 7:14 AM by heinrich

    ManyToOne to a composite primary key

    burnayev

      I've got what I think is a straightforward many-to-one to a composite primary key, which doesn't work as written. Here we go:

      User entity reads like this:
      @Entity
      @Table(name = "CTVUSERS")
      @IdClass(UserPK.class)
      @SequenceGenerator(name = "UserSeq", sequenceName = "SQ_USER")
      public class User {
      @Id
      @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "UserSeq")
      @Column(name = "CTVUSERS_KEY")
      private Long userKey;

      @Id
      @Column(name = "CTVUSERS_START_DATE")
      private Date startDate;

      @Id
      @Column(name = "CTVUSERS_END_DATE")
      private Date endDate;
      ...
      }

      The UserPK is defined like this:
      public class UserPK implements Serializable {
      private static final long serialVersionUID = -7720874756224520523L;

      private Long userKey;

      private Date startDate;

      private Date endDate;

      public UserPK() {
      }

      @Override
      public boolean equals(Object obj) {
      if (!(obj instanceof UserPK))
      return false;
      UserPK userPK = (UserPK) obj;
      SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy");
      return userKey.equals(userPK.userKey) && formatter.format(startDate).equals(formatter.format(userPK.startDate))
      && formatter.format(endDate).equals(formatter.format(userPK.endDate));
      }

      @Override
      public int hashCode() {
      return userKey.hashCode() * startDate.hashCode() * endDate.hashCode();
      }
      }


      UserDistrict entity goes as follows:
      @Entity
      @Table(name = "CLRUS2DI")
      @SequenceGenerator(name = "DistrictUserSeq", sequenceName = "SQ_DISTRICT_USER")
      public class DistrictUser {
      @Id
      @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "DistrictUserSeq")
      @Column(name = "CLRUS2DI_KEY")
      private Long id;

      @ManyToOne(cascade = CascadeType.ALL)
      @JoinColumns( { @JoinColumn(name = "CLRUS2DI_USERS_KEY", referencedColumnName="CTVUSERS_KEY"),
      @JoinColumn(name = "CLRUS2DI_BEGIN_DATE", referencedColumnName="CTVUSERS_START_DATE"),
      @JoinColumn(name = "CLRUS2DI_END_DATE", referencedColumnName="CTVUSERS_END_DATE") })
      private User user;
      ...
      }

      When I deploy the above I get:
      Caused by: org.hibernate.MappingException: Unable to find column with logical name: CTVUSERS_KEY in org.hibernate.mapping.Table(CTVUSERS) and its related supertables and secondary tables
      at org.hibernate.cfg.Ejb3JoinColumn.checkReferencedColumnsType(Ejb3JoinColumn.java:346)
      at org.hibernate.cfg.BinderHelper.createSyntheticPropertyReference(BinderHelper.java:80)
      at org.hibernate.cfg.FkSecondPass.doSecondPass(FkSecondPass.java:43)
      at org.hibernate.cfg.AnnotationConfiguration.secondPassCompile(AnnotationConfiguration.java:233)
      at org.hibernate.cfg.Configuration.buildMappings(Configuration.java:997)
      at org.hibernate.ejb.Ejb3Configuration.buildMappings(Ejb3Configuration.java:722)
      at org.hibernate.ejb.EventListenerConfigurator.configure(EventListenerConfigurator.java:161)
      at org.hibernate.ejb.Ejb3Configuration.createEntityManagerFactory(Ejb3Configuration.java:567)
      at org.hibernate.ejb.Ejb3Configuration.createContainerEntityManagerFactory(Ejb3Configuration.java:245)
      at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:108)
      at org.jboss.ejb3.entity.PersistenceUnitDeployment.start(PersistenceUnitDeployment.java:260)


      If I remove the many-to-one from DistrictUsers everything works fine.

      If I remove referenceColumnName's from the many-to-one specification, the code is deployed fine but then I have the following exception in runtime:
      Caused by: java.sql.SQLException: ORA-00904: "USER10_"."ENDDATE": invalid identifier

      at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112)
      at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:331)
      at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:288)
      at oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:743)
      at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:216)
      at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:799)
      at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:1039)
      at oracle.jdbc.driver.T4CPreparedStatement.executeMaybeDescribe(T4CPreparedStatement.java:839)
      at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1132)
      at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3285)
      at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3329)
      at org.jboss.resource.adapter.jdbc.WrappedPreparedStatement.executeQuery(WrappedPreparedStatement.java:211)
      at org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:139)
      at org.hibernate.loader.Loader.getResultSet(Loader.java:1669)
      at org.hibernate.loader.Loader.doQuery(Loader.java:662)
      at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:224)
      at org.hibernate.loader.Loader.loadEntity(Loader.java:1785)

      which is expected as the column names are different

      Any clues?

        • 1. Re: ManyToOne to a composite primary key
          epbernard

          First of all
          GeneratedValue cannot be used with composite primary keys

          Second, the column definitions should be set on the getters of UserPK, not on the User entity

          • 2. Re: ManyToOne to a composite primary key
            heinrich

            Hi Emmanuel,

            i think i have nearly the same problem.
            I have a database table with a composite pk consisting of a auto-gen id and a fk.
            As you mentioned before, auto-gen values are not allowed in composite pk.
            But, is there a solution for this cases?
            I think this is not a very exotic database architecture.

            Greetings

            Martin