Java Hibernate JPA映射,用于引用复合键列但没有外键关联的列

Java Hibernate JPA映射,用于引用复合键列但没有外键关联的列,java,database,hibernate,jpa,orm,Java,Database,Hibernate,Jpa,Orm,给定的模式不是真实的;这就是一个例子。这项工作对于ORM将POJO映射到无法更改的遗留数据库模式非常有用 两张桌子,一人一车: Person具有firstName和lastName的复合键 Car在其自身的OneToOne、可为空的列中引用Person.lastName 在数据库模式中,Person和Car不相关;没有外键 数据库表 class Person { @Id @Column(name="first_name") String firstName;

给定的模式不是真实的;这就是一个例子。这项工作对于ORM将POJO映射到无法更改的遗留数据库模式非常有用

两张桌子,一人一车:

  • Person具有firstName和lastName的复合键
  • Car在其自身的OneToOne、可为空的列中引用Person.lastName
  • 在数据库模式中,Person和Car不相关;没有外键
数据库表

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;
}
对于给定的示例JPA注释,Hibernate错误为:

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

我希望在检索汽车对象时使用正确的Person对象。同样,模式无法更改。

您可以使用
@embeddedeble
@EmbeddedId
创建复合键并将其与实体映射。例如:

@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 */
 }

希望这能解决您的问题

在hibernate文档中列出了几种用于映射复合标识符的选项:

hibernate文档包含了一个关于使用IdClass注释的警告

警告:此方法从EJB继承2天,我们 建议不要使用它。但是,毕竟这是你的申请和 Hibernate支持它

尽管如此,您的模型仍存在一些问题。如果事实上,车主的姓氏不是唯一的,那么车主之间的关系怎么可能是一对一的呢?在我看来,这辆车的车主关系必须是一对多的关系。换句话说,如果某人的姓氏确实是唯一的,那么它应该被用作唯一的主键,从而简化模型

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

Ashish,我最初使用了这个模式,但决定删除那个额外的层,因为我的@Id示例工作原理相同,而且更易于阅读和理解。我试图非常清楚地表明模型不会改变。Hibernate似乎不支持关联这些不相关的实体。因此,使用查询可能是强制关联的唯一方法。
@Embeddable
class PersonId {
    String firstName;
    String lastName;
}

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

    @Id
    String lastName;
}
@Entity
class Car {
    @JoinColumn(name="owner_last_name", referencedColumnName="last_name")
    @OneToMany
    Set<Person> owners;
}
"select Person person, Car car where person.lastName = car.lastName and car.id=?"