OneToOne双向映射外键自动填充
OneToOne bidirectional mapping foreign key auto fill
我有两个表之间的一对一关系,但外键在我不需要映射的表上,DBA 这样做是为了将来的更改。
假设我们有User和Address,今天每个用户只有一个地址,会这样映射,但是DBA相信以后可能是一对多的映射,所以user的外键在地址上,但应用程序有用户实例,这对于自动获取地址很重要。
我们做对了,如下:
@Entity
@Table(name = "user")
class User {
@Id
@Column(name = "user_id")
private Long id;
//...
@OneToOne(cascade = CascadeType.MERGE, mappedBy = "user")
private Address address; // this attribute is crucial
}
@Entity
@Table(name = "address")
class Address {
@Id
@Column(name = "address_id")
private Long id;
@OneToOne
@JoinColumn(name = "user_id")
private User user; // this attribute is not needed for the business at all, but mappedBy requires it
//...
}
数据库:
-- SQL:
CREATE TABLE user
(
user_id INT NOT NULL,
-- ...
CONSTRAINT user_pk PRIMARY KEY (user_id)
);
CREATE TABLE address
(
address_id INT NOT NULL,
user_id INT NOT NULL,
-- ...
CONSTRAINT address_pk PRIMARY KEY (address_id),
CONSTRAINT address_user_id_fk FOREIGN KEY (user_id) REFERENCES user (user_id),
CONSTRAINT address_user_id_uk UNIQUE (user_id) -- it says it's a one to one relation for now, if in the future it won't be anymore, just remove this constraint
);
问题是当用新的 address 实例保存用户实例时,用户的 address 属性是 null
,所以我希望 Hibernate 足够聪明,可以将它设置为用户实例的值它来自.
找了几天的解决办法,还是没找到解决方法,同时手动设置了这个值,但我想我不需要这样做.
如果不需要"private User user",删除它并同时删除'User'实体中的mappedBy。使用单向关系。
在您的示例中,mappedBy 意味着关联的所有者是 'Address' 实体,因此保存 Adress 实例而不是 User 实例。喜欢:
adress.setUser(user);
session.save(adress);
您需要添加 CasecadeType.PERSIST 以使创建地址与创建用户串联。
在您的 java 代码中,您需要做:
user.setAddress(address);
address.setUser(user);
session.persist(user);
然后您的用户将创建一个地址。
如果你只是想读取一个新创建的用户的地址,那么你需要做:
// your code to persist a new User and Address
session.flush();
session.refresh(user);
如果这不是您想要的,那么您需要分享您自己的 Java 代码并详细说明您的期望。
标准解决方案是正确更新 bidirectional association 的两侧(尽管只有拥有方需要更新才能将关联保存到数据库)。添加到 Address
setter 中 User
class:
public void setAddress(Address address) {
this.address = address;
address.setUser(this);
}
此外,您可能希望扩展 address
属性 的级联选项以包括 PERSIST
,以便它始终与其用户一起持久保存:
@OneToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, mappedBy = "user")
private Address address;
然后您可以为用户设置一个地址并保留两者:
user.setAddress(address);
session.persist(user);
我有两个表之间的一对一关系,但外键在我不需要映射的表上,DBA 这样做是为了将来的更改。
假设我们有User和Address,今天每个用户只有一个地址,会这样映射,但是DBA相信以后可能是一对多的映射,所以user的外键在地址上,但应用程序有用户实例,这对于自动获取地址很重要。
我们做对了,如下:
@Entity
@Table(name = "user")
class User {
@Id
@Column(name = "user_id")
private Long id;
//...
@OneToOne(cascade = CascadeType.MERGE, mappedBy = "user")
private Address address; // this attribute is crucial
}
@Entity
@Table(name = "address")
class Address {
@Id
@Column(name = "address_id")
private Long id;
@OneToOne
@JoinColumn(name = "user_id")
private User user; // this attribute is not needed for the business at all, but mappedBy requires it
//...
}
数据库:
-- SQL:
CREATE TABLE user
(
user_id INT NOT NULL,
-- ...
CONSTRAINT user_pk PRIMARY KEY (user_id)
);
CREATE TABLE address
(
address_id INT NOT NULL,
user_id INT NOT NULL,
-- ...
CONSTRAINT address_pk PRIMARY KEY (address_id),
CONSTRAINT address_user_id_fk FOREIGN KEY (user_id) REFERENCES user (user_id),
CONSTRAINT address_user_id_uk UNIQUE (user_id) -- it says it's a one to one relation for now, if in the future it won't be anymore, just remove this constraint
);
问题是当用新的 address 实例保存用户实例时,用户的 address 属性是 null
,所以我希望 Hibernate 足够聪明,可以将它设置为用户实例的值它来自.
找了几天的解决办法,还是没找到解决方法,同时手动设置了这个值,但我想我不需要这样做.
如果不需要"private User user",删除它并同时删除'User'实体中的mappedBy。使用单向关系。
在您的示例中,mappedBy 意味着关联的所有者是 'Address' 实体,因此保存 Adress 实例而不是 User 实例。喜欢:
adress.setUser(user);
session.save(adress);
您需要添加 CasecadeType.PERSIST 以使创建地址与创建用户串联。
在您的 java 代码中,您需要做:
user.setAddress(address);
address.setUser(user);
session.persist(user);
然后您的用户将创建一个地址。
如果你只是想读取一个新创建的用户的地址,那么你需要做:
// your code to persist a new User and Address
session.flush();
session.refresh(user);
如果这不是您想要的,那么您需要分享您自己的 Java 代码并详细说明您的期望。
标准解决方案是正确更新 bidirectional association 的两侧(尽管只有拥有方需要更新才能将关联保存到数据库)。添加到 Address
setter 中 User
class:
public void setAddress(Address address) {
this.address = address;
address.setUser(this);
}
此外,您可能希望扩展 address
属性 的级联选项以包括 PERSIST
,以便它始终与其用户一起持久保存:
@OneToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, mappedBy = "user")
private Address address;
然后您可以为用户设置一个地址并保留两者:
user.setAddress(address);
session.persist(user);