我想用JPA / Hibernate建模两个实体,一个组和一个帐户之间的关系。一个帐户可以有多个组,但反之亦然,因此我们在帐户和组之间存在OneToMany关系。
我的同事建议对实体Account
和Group
进行建模,如
public class Account {
private List<Group> groups = new ArrayList<Group>();
public Account() {}
public void setGroups(List<Group> usergroups) {
this.groups = groups;
}
@OneToMany(mappedBy = "account")
public List<Group> getGroups() {
return groups;
}
}
和
public class Group {
private String name;
private Account account;
public Group() {}
public Group(String name, Account account) {
this.name = name;
addToAccount(account);
}
public void addToAccount(Account account) {
setAccount(account);
List<Group> accountGroups = account.getGroups();
accountGroups.add(this);
}
@ManyToOne
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
}
我现在的问题是在addToAccount
的构造函数中使用辅助方法Group
。根据我的工作同事的说法,这种方法是必要的,因为我们需要更新两个实体之间的双向关系,以确保两个实体的内存模型一致。
但是我相信在构造函数中调用方法addToAccount
并不是一个好主意,因为
List
的{{1}}是懒惰的
抓取,所以调用方法
Group
需要开放
交易。所以构造函数
addToAccount
只能在一个内部调用
开放交易。在我看来,这是一个非常烦人的限制。
作为参数给出的Group
对象
到Account
的构造函数是
由构造函数更改。在我看来,这是一个
Group
令人惊讶的副作用
构造函数,不应该发生。
我的建议是更好地使用像
这样的简单构造函数Group
手动处理双向关系。但也许我错了。在构造hibernate实体时,是否应该如何处理双向关系?
答案 0 :(得分:3)
在我们的项目中,我们通常会尽量避免双向关联。
一个原因是你的模型中有一个循环可能会产生问题,如果你想以某种方式序列化它,例如假设你想要序列化Account
而你的序列化算法不够聪明你就结束了无限循环(因为Group
有一个返回Account
的引用)。
第二个原因是我发现只有一种方法来导航模型更清楚。我通常做的是删除帐户实体中的OneToMany关联,并在需要收集特定Group
的所有Account
时使用存储库调用(但这可能取决于您的用例和个人品味)。
第三,如果你摆脱addToAccount方法并使用字段访问权限,你可以使你的类不可变,这是一件好事。
答案 1 :(得分:0)
根据我的经验,你完全按照惯例做到这一点。我的问题更多的是关于结构(我希望还有比上面提供的示例更多)关于你为什么要直接从集团操纵账户的问题。
我还怀疑这是OneToMany还是ManyToMany情况(通常多个帐户可以属于一个组,多个组可以属于一个帐户,但它们都属于您的特定会计方案的语义...)无论如何:你做得对,虽然我质疑(在这个确切的情况下)为什么你想直接操纵帐户(除非它是懒惰加载)这是完全没问题的。
[您可能需要添加一些级联规则,以便根据您的配置保持正常。]
您应该注意到,通过映射到帐户,您已将其有效地添加到帐户列表中。当数据库下一次查询以创建该列表时,它将通过查找来自Account实体的引用来填充列表。
简而言之 - &gt;
public void Group.setAccounts(Account a)
{
this.account = a;
}
实际上与您上面所做的相同。数据库将使用类似于:
的内容查询和填充List//Pseudo SQL
SELECT g.id FROM Group g WHERE g.account_id = :account_id
因此,除了延迟加载(您可能想要或可能不想要的东西)之外,添加到组是不必要的,因为List是由查询定义的。
(不要太难,看起来很简单。我希望通过长篇解释让您了解JPA中发生的事情)