java - 如何在没有数据冗余的情况下与JPA实体建立递归关系?

标签 java spring hibernate jpa spring-data-jpa

我已经研究过如何建立递归关系,并且我已经知道如何去做,但我无法避免这种类型的关系中的冗余。我有一个具有“ 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() 时,结果是相同的。该代码似乎也是多余的,因为我是第一次尝试这种关系,而且我的做法与处理其他双向多对多关系的方式相同

最佳答案

重要的问题是:重复的问题是什么?

我想说当前的变体是对此进行建模的默认正确方法。

替代方案可能是:

  1. 写入时,仅填充一个方向,在数据库端使用触发器来添加相反方向。这避免了将数据两次传输到数据库。仅当相关实体重新加载后,反向方向才会可见,这通常意味着仅当您使用新 session 时。

  2. 写作时,只填写一个方向。将关系映射到一个 View ,该 View 在切换了两个用户 ID 的基础表上进行所有联合。您需要在该 View 上插入和删除触发器。对您的应用程序的影响与变体 1 相同。

  3. 您可以建模 Friendship作为其自己的实体,具有 Set<User>固定为始终有两个条目。

  4. 如果这种关系对您的应用程序很重要,那么使用像 Neo4j 这样的专门数据库可能是值得的。它带有自己的 Spring Data Neo4J。

关于java - 如何在没有数据冗余的情况下与JPA实体建立递归关系?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72295618/

相关文章:

java.util.zip.ZipException : invalid CEN header (bad signature)

java - 在 Java 中将整数转换为罗马数字

java - Sitemesh,无法构建工厂 : com. opensymphony.module.sitemesh.factory.DefaultFactory:

java - 我无法运行我的第一个 Spring 应用程序,Hello World?我已经添加了所有 jar

java - 找不到 org.springframework.web.servlet.DispatcherServlet 类

java - 存储动态 JPA 查询

Java PriorityQueue 似乎在调用 add() 时更改了之前添加的值

Java:检查命令行参数是否为空

java - hibernate - 为mysql连接创建字符串类型的主键

linux 中的 java ${user.home} 变量