我想通过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)
后。数据成功保存...没有任何关系信息。
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);
但我不明白,为什么第一个配置(用户是拥有方)不能正常工作。
答案 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现在外键更新得很好。