在构造hibernate实体时如何处理双向关系



我想用JPA/Hibernate建模两个实体,一个组和一个帐户之间的关系。一个帐户可以有几个组,反之则不行,因此我们在帐户和组之间有一个OneToMany关系。我的同事建议对实体AccountGroup进行建模,如

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方法不是一个好主意,因为

  1. Groups的List是惰性的已获取,也就是调用方法addToAccount需要打开事务。的构造函数Group只能在类中调用打开的事务。在我看来,这是一个非常烦人的限制。

  2. 作为参数给出的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中发生了什么)

相关内容

  • 没有找到相关文章

最新更新