JPA:OneToOne关系所有者

时间:2017-05-14 14:05:02

标签: hibernate jpa

我想通过User.idAddress.user_id

建立两个模型之间的关系

创建了两个具有一对一关系的表:

@Entity()
@Table(name = "user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "id", referencedColumnName = "user_id")
    private Address address;

    public int getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

}



@Entity
@Table(name = "address")
public class Address extends com.mezoline.domain.common.Entity {

    @Id
    @GeneratedValue
    private int id;

    @OneToOne(mappedBy = "address")
    private User user;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

}

在这里,我已经可以看到问题:hibernate没有生成数据库列Address.user_id我的预期。

我创建了Address个实例并将其添加到User

    User user = entityManager.find(User.class, 69);
    Address address = new Address();
    address.setCity("Тест");
    userTransaction.begin();
    user.setAddress(address);
    entityManager.merge(user);
    userTransaction.commit();

致电merge(user)后。数据成功保存...没有任何关系信息。

UPD:

使用下面的配置,JPA将创建关系列Address.user_id(仅交换关系所有者)

public class User { 
    ...
    @OneToOne(cascade = CascadeType.ALL, mappedBy = "user")
    private Address address;
    ...
}

public class Address {
    ....
    @OneToOne()
    @JoinColumn(name = "user_id")
    private User user;
    ....
}

但是在保存后,Address.user_id为null ...(其他列正在填充)

UPD2:

感谢。第二个配置工作正常,当设置反面关系字段时(如评论中所建议):

Address address = createAddress();
address.setUser(user);
user.setAddress(address);

但我不明白,为什么第一个配置(用户是拥有方)不能正常工作。

4 个答案:

答案 0 :(得分:3)

那是因为您对初始配置的期望存在逻辑错误。

您声明User是该关系的拥有方面。 拥有表示表示关系的外键将保存在USER表中,而不是Address表中。

与此同时,您使用User.address@JoinColumn(name = "id", referencedColumnName = "user_id")进行了注释。基本上,我认为您正在尝试强制ADRESS表来保存外键。但在这种情况下, Adress应该是拥有方

如果您希望初始配置有效,那么您应该做的就是用JoinColumn替换当前的@JoinColumn(name = "address_id")注释。外键将最终出现在USER表中。持久化实体时,必须设置User.address;设置Address.user是可选的。

如果您绝对需要在ADDRESS表中使用密钥,请将Address表设为拥有方(然后您必须确保Address.user设置为持续时间;但是,除非您明确地保留User.address实体,否则您仍然希望设置Address以使级联工作。

答案 1 :(得分:1)

因为它是双向 One-to-One,您还需要在保持父/超级之前将反面设置为所谓的父实体实体。

Address addr =  new Address()
user.setAddress(addr);
addr.setUser(user);
session.save(user);

答案 2 :(得分:1)

我会留在原始配置中,用户是拥有者。对我的架构更有意义。

关于Address上的user_id列,您必须确保在关系的两端都设置了依赖关系。因此,您的转换方法应包含以下内容:

if (user.getAddress() == null) {
    Address address = createAddress();
    address.setUser(user);
    user.setAddress(address);        
}

答案 3 :(得分:-2)

@crizzis 解释得很好,我试图保存一个 Employee 对象和 Address 对象并使 Address 表具有外键,但是 Employee 对象拥有关系,按照您的指示将所有权更改为 Employee现在外键更新得很好。