JPA:OneToOne 关系所有者
Posted
技术标签:
【中文标题】JPA:OneToOne 关系所有者【英文标题】:JPA: OneToOne relation owner 【发布时间】:2017-05-14 14:05:01 【问题描述】:我想通过User.id
和Address.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)
之后。数据成功保存...没有任何关系信息。
更新:
使用下面的配置,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
为空...(正在填充其他列)
UPD2:
谢谢。第二个配置工作正常,何时设置反向关系字段(如 cmets 中所建议):
Address address = createAddress();
address.setUser(user);
user.setAddress(address);
但我不明白,为什么第一个配置(用户是拥有方)不起作用。
【问题讨论】:
【参考方案1】:这是因为您对初始配置的期望存在逻辑错误。
您声明User
是关系的拥有方。 Owning 表示表示关系的外键将保存在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
实体)。
【讨论】:
【参考方案2】:因为是双向One-to-One
,所以在持久化父/超实体之前,还需要将反面设置为所谓的父实体。
Address addr = new Address()
user.setAddress(addr);
addr.setUser(user);
session.save(user);
【讨论】:
【参考方案3】:我会保留原始配置,其中用户是拥有方。关于您的架构,这对我来说更有意义。
关于地址.. 上的user_id
列,您必须确保在关系的双方都设置了依赖关系。因此,您的交易方法应包含以下内容:
if (user.getAddress() == null)
Address address = createAddress();
address.setUser(user);
user.setAddress(address);
【讨论】:
【参考方案4】:@crizzis 解释得很好,我试图保存一个 Employee 对象和 Address 对象并使 Address 表具有外键,但是 Employee 对象拥有关系,在按照您的指示将所有权更改为 Employee现在外键更新正常。
【讨论】:
请避免发布“谢谢”答案。如果有什么对你有用,请投票赞成:)以上是关于JPA:OneToOne 关系所有者的主要内容,如果未能解决你的问题,请参考以下文章
hibernate/jpa double OneToOne 与一个实体的双向关系
SpringData JPA中一对一关系映射注解@OneToOne应用
jpa hibernate @OneToOne @JoinColumn referencedColumnName 被忽略