2

Lets say I have these tables:

Table A has a composite primary key on two fields:

  • Employee ID (String)
  • Transaction ID (Long)

Table B also has a composite primary key, but on three fields:

  • Employee ID (String)
  • Transaction ID (Long)
  • Date (Date)

In table B, there is a Foreign Key on Employee ID and Transaction ID called "FK1" (for simplicity).

Since the composite id used in table A is used across several mapped hibernate classes, I create a class I can reuse:

@Embeddable
public class EmployeeTransactionComposite {

    private String employeeId;
    private Long transactionId;

}

So, the class mapped to Table A looks like this:

public ClassA implements Serializable {

    private EmployeeTransactionComposite id;
    // rest of fields

    @EmbeddedId
    public EmployeeTransactionComposite getId() {
        return id;
    }
}

The class mapped to table B looks like this:

public ClassB implements Serializable {

    private ClassBCompositeId id;
    // fields

    @EmbeddedId
    public getId() {
        return this.id;
    }

    @Embeddable
    public class ClassBCompositeId implements Serializable {

        private EmployeeTransactionComposite composite;
        private Date date;

        @ManyToOne
    @ForeignKey(name="FK1")
        public EmployeeTransactionComposite getComposite() {
            return composite;
        }

        @Column(name="THEDATE")
        public Date getDate() {
            return date;
        }
    }
}

Obviously I wouldn't be posting this if it was working. It blows up with a stacktrace like this:

Caused By: java.lang.NullPointerException
at org.hibernate.cfg.Configuration.processFkSecondPassInOrder(Configuration.java:1419)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1359)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1728)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1779)
at org.springframework.orm.hibernate4.LocalSessionFactoryBuilder.buildSessionFactory(LocalSessionFactoryBuilder.java:189)
Truncated. see log file for complete stacktrace

This is a mapping to a legacy schema, so alterations are not possible. Can anyone help?

Jason
  • 3,943
  • 12
  • 64
  • 104

1 Answers1

2

A ManyToOne never points on a primary key class, but always on an entity. Thus, this mapping is incorrect:

@ManyToOne
@ForeignKey(name="FK1")
public EmployeeTransactionComposite getComposite() {
    return composite;
}

I recommend not defining any association in the primary key classes, and only defining basic columns (or embeddables containing basic columns). Then define the association in the entity itself, and use the @MapsId annotation on this association to tell Hibernate that this association uses the same columns as the ones used to map the ID.

The documentation contains an example of mapping that does exactly what you're trying to do:

An embedded id can itself contains the primary key of an associated entity.

@Entity
class Customer {
   @EmbeddedId CustomerId id;
   boolean preferredCustomer;

   @MapsId("userId")
   @JoinColumns({
      @JoinColumn(name="userfirstname_fk", referencedColumnName="firstName"),
      @JoinColumn(name="userlastname_fk", referencedColumnName="lastName")
   })
   @OneToOne User user;
}

@Embeddable
class CustomerId implements Serializable {
   UserId userId;
   String customerNumber;

   //implements equals and hashCode
}

@Entity 
class User {
   @EmbeddedId UserId id;
   Integer age;
}

@Embeddable
class UserId implements Serializable {
   String firstName;
   String lastName;

   //implements equals and hashCode
}
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Okay, let me try it and if it works I'll come back and accept the answer. I appreciate you taking the time to help. – Jason May 18 '12 at 13:10
  • Hi JB, sorry to trouble you, I still have some questions on this topic for which I have created a post, can you please respond to it: http://stackoverflow.com/questions/25236449/understanding-mapsid-annotation-in-hibernate – Chaitanya Aug 12 '14 at 18:33