4

我想用 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;
    }
}

我现在的问题是addToAccount关于Group. 根据我的工作同事的说法,这种方法是必要的,因为我们需要从双方更新两个实体之间的双向关系,以确保两个实体的内存模型一致。

但是我相信在构造函数中调用该方法addToAccount不是一个好主意,因为

  1. Listof s 是延迟获取的Group,因此调用该方法 addToAccount需要一个打开的事务。所以 Group只能在打开的事务中调用构造函数。在我看来,这是一个非常烦人的限制。

  2. 作为构造函数的参数给出的Account对象Group由构造函数更改。在我看来,这是构造函数的一个令人惊讶的副作用,Group 不应该发生。

我的建议是更好地使用一个简单的构造函数,比如

 public Group(String name, Account account) {
            this.name = name;
            this.account = account;
        }

并手动处理双向关系。但也许我错了。在构建休眠实体时,是否有一种常见的方式来处理双向关系?

4

2 回答 2

3

在我们的项目中,我们通常会尽量避免双向关联。

一个原因是你的模型中有一个循环,如果你想以某种方式对其进行序列化,它可能会产生问题,例如,假设你想序列化一个Account并且你的序列化算法不够聪明,你最终会出现一个无限循环(因为Group有对 ) 的引用Account

第二个原因是我发现只有一种方法来导航模型更清楚。我通常做的是删除 Account 实体中的 OneToMany 关联,并在我需要收集Group特定的所有 s时使用存储库调用Account(但这可能取决于您的用例和个人品味)。

第三,如果您摆脱 addToAccount 方法并使用字段访问,您可以使您的类不可变,这是一件好事。

于 2011-07-06T15:28:03.960 回答
0

根据我的经验,您正在按照通常的方式进行操作。我的问题更多是关于结构(我希望比上面提供的示例更多)关于为什么要直接从集团操纵帐户。

我还质疑这是 OneToMany 还是 ManyToMany 情况(通常多个帐户可以属于一个组,多个组可以属于一个帐户,但这一切都在您的特定会计方案的语义中......)无论如何:你'做得对,尽管我质疑(在这种情况下)为什么要直接操纵帐户(除非它是延迟加载的),但这完全没问题。

[您可能需要添加一些级联规则,以便它根据您的配置正确保留。]

您应该注意,通过映射到帐户,您实际上已将其添加到帐户列表中。当数据库下次查询以创建该列表时,它将通过查找来自 Account 实体的引用来填充列表。

简而言之->

public void Group.setAccounts(Account a)
{
  this.account = a;
}

实际上等同于您在上面所做的。数据库将使用类似于以下内容的内容查询和填充列表:

//Pseudo SQL
    SELECT g.id FROM Group g WHERE g.account_id = :account_id

因此,除了延迟加载(您可能想要或可能不想要的东西)之外,添加到组是不必要的,因为 List 是由查询定义的。

(不要让它太难,它看起来很简单。我希望冗长的解释能让你对 JPA 中发生的事情有所了解)

于 2011-07-06T14:58:59.367 回答