我想用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;
}
}
我现在的问题是关于Group
的构造函数中辅助方法addToAccount
的使用。根据我的同事的说法,这种方法是必要的,因为我们需要从两边更新两个实体之间的双向关系,以确保两个实体的一致的内存模型。
然而,我认为在构造函数中调用addToAccount
方法不是一个好主意,因为
Group
s的List
是惰性的已获取,也就是调用方法addToAccount
需要打开事务。的构造函数Group
只能在类中调用打开的事务。在我看来,这是一个非常烦人的限制。作为参数给出的
Account
对象Group
的构造函数为由构造函数更改。在我看来,这是一个Group
的惊人副作用
public Group(String name, Account account) {
this.name = name;
this.account = account;
}
,手动处理双向关系。但也许我错了。在构造hibernate实体时,是否有一种处理双向关系的通用方法?
在我们的项目中,我们通常会尽量避免双向关联。
一个原因是你的模型中有一个循环,如果你想以某种方式序列化它,可能会产生问题,例如,假设你想序列化一个Account
,而你的序列化算法不够聪明,你最终会出现一个无限循环(因为Group
有一个对Account
的引用)。
第二个原因是我发现只有一种方法来导航模型更清晰。我通常做的是删除帐户实体中的OneToMany关联,并在需要收集特定Account
的所有Group
时使用存储库调用(但这可能取决于您的用例和个人品味)。
第三,如果你摆脱addToAccount方法并使用字段访问,你可以使你的类不可变,这是一件好事
根据我的经验,您正在做的正是通常所做的。我的问题更多的是关于结构(我希望有比上面提供的示例更多的内容),以及为什么您想直接从组中操作帐户。
我也质疑这是一个OneToMany还是一个manymany情况(通常多个帐户可以属于一个组,多个组可以属于一个帐户,但这都是在你的特定会计方案的语义…)无论如何:你做得对,虽然我质疑(在这种情况下)为什么你想要直接操纵帐户(除非它是惰性加载)这是完全好的。
[你可能需要添加一些级联规则,以便它根据你的配置正确地持续]
您应该注意到,通过映射到Account,您已经有效地将其添加到Account的List中。当数据库下一次查询创建该列表时,它将通过查找Account实体中的引用来填充该列表。
总之->
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中发生了什么)