我已经研究过如何建立递归关系,并且我已经知道如何去做,但我无法避免这种类型的关系中的冗余。我有一个具有“ friend ”属性的用户类。用户可以与许多其他用户成为 friend ,其他用户也可以与其中一个用户成为 friend 。所以我做了以下事情:
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "friends",
joinColumns = @JoinColumn(name = "user1_id"),
inverseJoinColumns = @JoinColumn(name = "user2_id"))
private List<User> friends = new ArrayList<User>();
为了输入数据,我使用以下服务函数。
public void addFriend(User requester, User requested) throws DataNotFoundException{
requester.getFriends().add(requested);
requested.getFriends().add(requester);
update(requested);
}
每次我更新“请求”时,它都会获取与其“请求者”相关的实体并更新它。最初我以为这是一个级联问题,但我看到级联默认是禁用的,并且所有选项都是将操作传播给子级的不同方式。
最后,这会在我的表中创建 2 行,其中包含冗余数据
user1_id | user2_id
1 2
2 1
我只想创建一条线供关系双方使用。
我考虑过为此创建一个自定义查询,但从设计的角度来看,它似乎不是最合适的解决方案。因为它会产生我需要做的定制的滚雪球。
编辑:当我从任一侧删除 getFriends().add() 时,结果是相同的。该代码似乎也是多余的,因为我是第一次尝试这种关系,而且我的做法与处理其他双向多对多关系的方式相同
最佳答案
重要的问题是:重复的问题是什么?
我想说当前的变体是对此进行建模的默认正确方法。
替代方案可能是:
写入时,仅填充一个方向,在数据库端使用触发器来添加相反方向。这避免了将数据两次传输到数据库。仅当相关实体重新加载后,反向方向才会可见,这通常意味着仅当您使用新 session 时。
写作时,只填写一个方向。将关系映射到一个 View ,该 View 在切换了两个用户 ID 的基础表上进行所有联合。您需要在该 View 上插入和删除触发器。对您的应用程序的影响与变体 1 相同。
您可以建模
Friendship
作为其自己的实体,具有Set<User>
固定为始终有两个条目。如果这种关系对您的应用程序很重要,那么使用像 Neo4j 这样的专门数据库可能是值得的。它带有自己的 Spring Data Neo4J。
关于java - 如何在没有数据冗余的情况下与JPA实体建立递归关系?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72295618/