Matt
Matt

Reputation: 3244

Hibernate JPA mapping for column referencing a composite key column, but no foreign key association

The given schema is not real; it is an example. This effort is useful for ORM mapping POJOs to legacy database schemas that cannot change.

Two tables, Person and Car:

Database Tables

 -------------------------   -------------------------
| Person                  | | Car                     |
|-------------------------| |-------------------------
| <PK> first_name: String | | owner_last_name: String |
| <PK> last_name: String  |  -------------------------
 -------------------------

Java Classes

class Person {
    @Id
    @Column(name="first_name")
    String firstName;

    @Id
    @Column(name="last_name")
    String lastName;
}

class Car {
    @JoinColumn(name="owner_last_name", referencedColumnName="last_name")
    @OneToOne(optional = true)
    Person owner;
}

With the given example JPA annotations, the Hibernate error is:

org.hibernate.AnnotationException: referencedColumnNames(last_name) of com.example.Car.owner referencing com.example.Person not mapped to a single property

I would like to have the correct Person object when retrieving the Car object. Again, the schema cannot change.

Upvotes: 0

Views: 1478

Answers (2)

Larry Chu
Larry Chu

Reputation: 106

There are several options for mapping a composite identifier which are listed in the hibernate documentation here:

http://docs.jboss.org/hibernate/orm/4.3/manual/en-US/html/ch05.html#mapping-declaration-id

The hibernate documentation includes a warning against using the IdClass annotation.

Warning This approach is inherited from the EJB 2 days and we recommend against its use. But, after all it's your application and Hibernate supports it.

@Embeddable
class PersonId {
    String firstName;
    String lastName;
}

@Entity
@IdClass(PersonId.class)    
class Person {
    @Id
    String firstName;

    @Id
    String lastName;
}

That being said, there are a few problems with your model. How can Car's owner relationship be one-to-one if in fact the last name in Person is not unique? It seems to me that Car's owner relationship must be one-to-many. Stated differently, if Person's last name is truly unique, then it should be used as the sole primary key thus simplifying the model.

@Entity
class Car {
    @JoinColumn(name="owner_last_name", referencedColumnName="last_name")
    @OneToMany
    Set<Person> owners;
}

Perhaps it would be simpler to just create the entities without the relationships, and use a (criteria or hql) query to find the related objects.

Find all Persons who could possibly be owners of this car:

"select Person person, Car car where person.lastName = car.lastName and car.id=?"

Upvotes: 0

Ashish Jagtap
Ashish Jagtap

Reputation: 2819

You can use @Embeddeble and @EmbeddedId to create a composite key and map it with your Entity. For example:

@Embeddable
public class PersonCompositeID {

    @Column(name="first_name")
    String firstName;

    @Column(name="last_name")
    String lastName;

    //getter, setter methods
}

 @Entity
 @Table(name = "Person")
 public class Person {

     @EmbeddedId
     private PersonCompositeID  personCompositeID;

  /*setter getter methods */
 }

hope this will solve your problem

Upvotes: 0

Related Questions