Hibernate是否支持一对一关联作为pkeys?

时间:2010-04-14 14:37:29

标签: java hibernate orm entity-relationship

有人能告诉我Hibernate是否支持关联作为实体的密钥?我认为这将得到支持,但是我在使用任何代表这种方式的映射时遇到了很多麻烦。特别是,使用下面的直接映射:

@Entity
public class EntityBar
{
    @Id
    @OneToOne(optional = false, mappedBy = "bar")
    EntityFoo foo

    // other stuff
}

我得到一个org.hibernate.MappingException:“无法确定类型:EntityFoo,在表:ENTITY_BAR,对于列:[org.hibernate.mapping.Column(foo)]”

潜入代码似乎ID始终被视为值类型;即“任何通过值而不是通过引用持久化的东西。它本质上是一个Hibernate类型,连同零个或多个列。”我可以通过声明它的序列化来使我的EntityFoo成为一个值类型,但我不认为这会导致正确的结果。

我原本以为Hibernate会认为列的类型是整数(或者父类ID的实际类型),就像它与普通的一对一链接一样,但这并不是'当我也宣布它是一个ID时,似乎开始了。尝试将@OneToOne与@Id结合起来,我是否超越了可能的范围?如果是这样,那么如何合理地建立这种关系呢?

4 个答案:

答案 0 :(得分:2)

如果目标是拥有共享主键,那么(受 Java Persistence With Hibernate 样本的启发并在宠物数据库上测试):< / p>

@Entity
public class User {
    @Id
    @GeneratedValue
    private Long id;

    @OneToOne(cascade = CascadeType.ALL)
    @PrimaryKeyJoinColumn
    private Address shippingAddress;

    //...
}

这是首先插入并获取生成ID的“父”类。 Address看起来像这样:

@Entity
public class Address implements Serializable {
    @Id @GeneratedValue(generator = "myForeignGenerator")
    @org.hibernate.annotations.GenericGenerator(
        name = "myForeignGenerator",
        strategy = "foreign",
        parameters = @Parameter(name = "property", value = "user")
    )
    @Column(name = "ADDRESS_ID")
    private Long id;

    @OneToOne(mappedBy="shippingAddress")
    @PrimaryKeyJoinColumn
    User user;

    //...
}

使用上述实体,以下似乎表现得如预期:

User newUser = new User();
Address shippingAddress = new Address();
newUser.setShippingAddress(shippingAddress);
shippingAddress.setUser(newUser);            // Bidirectional
session.save(newUser);

保存Address时,插入的主键值与User属性引用的user实例的主键值相同。

加载UserAddress也是有效的。

如果我错过了什么,请告诉我。


PS:严格回答问题,根据Primary Keys through OneToOne Relationships

  

JPA 1.0不允许在OneToOne或ManyToOne上使用@Id,但JPA 2.0允许使用@Id。

,符合JPA 1.0标准的Hibernate版本

  

允许在@IdOneToOne映射*上使用ManyToOne注释。

我无法使用Hibernate EM 3.4(它适用于Hibernate EM 3.5.1,即JPA 2.0实现)。也许我做错了什么。

无论如何,使用共享主键似乎提供了有效的解决方案。

答案 1 :(得分:1)

是的,这是可能的。

使用Driver和DriverId类作为驱动程序的ID,查看以下示例。

@Entity
public class Drivers {

private DriversId id; //The ID which is located in another class

public Drivers() {
}

@EmbeddedId
@AttributeOverrides({
        @AttributeOverride(name = "personId", column = @Column(name = "person_id", nullable = false))})
@NotNull
public DriversId getId() {
    return this.id;
}
   //rest of class
}

这里我们使用personId作为Driver

的id

和DriversId类:

//composite-id class must implement Serializable
@Embeddable
public class DriversId implements java.io.Serializable {
private static final long serialVersionUID = 462977040679573718L;

private int personId;

public DriversId() {
}

public DriversId(int personId) {
    this.personId = personId;
}

@Column(name = "person_id", nullable = false)
public int getPersonId() {
    return this.personId;
}

public void setPersonId(int personId) {
    this.personId = personId;
}

public boolean equals(Object other) {
    if ((this == other))
        return true;
    if ((other == null))
        return false;
    if (!(other instanceof DriversId))
        return false;
    DriversId castOther = (DriversId) other;

    return (this.getPersonId() == castOther.getPersonId());
}

public int hashCode() {
    int result = 17;

    result = 37 * result + this.getPersonId();
    return result;
}
}

答案 2 :(得分:0)

您可以通过在EntityFoo和EntityBar之间共享主键来完成此操作:

@Entity
public class EntityBar
{
    @Id @OneToOne
    @JoinColumn(name = "foo_id")
    EntityFoo foo;

    // other stuff
}

@Entity
public class EntityFoo
{
    @Id @GeneratedValue
    Integer id;

    // other stuff
}

答案 3 :(得分:0)

您必须在此处使用@EmbeddedId代替@IdEntityFoo应为Embeddable

另一种方法是放置一个整数,OneToOne updatebleinstertable设置为false.