Java 同一类型实体的多对多关系

Java 同一类型实体的多对多关系,java,spring,hibernate,many-to-many,bidirectional-relation,Java,Spring,Hibernate,Many To Many,Bidirectional Relation,我有一个实体如下。我很好奇是否有可能建立一种关系,我将用下面的例子来描述: 我正在创建两个个人实体迈克尔和朱莉娅 我要把朱莉娅加入迈克尔的朋友组 之后,我以JSON响应的形式检索Michael,Julia在响应中可用。但当我找回朱莉娅时,她的朋友集是空的。我想通过保存友谊的一面来建立双向的友谊关系。我想让迈克尔在朱莉娅的朋友组里,不用做任何其他的手术。我认为它必须由Hibernate管理。有可能吗?我该怎么做 @ToString(exclude = "friends") // EDIT: th

我有一个实体如下。我很好奇是否有可能建立一种关系,我将用下面的例子来描述:

  • 我正在创建两个个人实体迈克尔朱莉娅
  • 我要把朱莉娅加入迈克尔的朋友组
  • 之后,我以JSON响应的形式检索Michael,Julia在响应中可用。但当我找回朱莉娅时,她的朋友集是空的。我想通过保存友谊的一面来建立双向的友谊关系。我想让迈克尔在朱莉娅的朋友组里,不用做任何其他的手术。我认为它必须由Hibernate管理。有可能吗?我该怎么做

    @ToString(exclude = "friends") // EDIT: these 2 exclusion necessary
    @EqualsAndHashCode(exclude = "friends")
    public class Person{
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Long id;
    
    @Column(name = "name",unique = true)
    private String name;
    
    @JsonIgnoreProperties("friends") // EDIT: will prevent the infinite recursion
    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(name = "FRIENDSHIP",
           joinColumns = @JoinColumn(name = "person_id", 
    referencedColumnName = "id"),
           inverseJoinColumns = @JoinColumn(name = "friend_id", 
    referencedColumnName = "id"))
    private Set<Person> friends;
    
    相关问题:

    更新了源代码,此版本工作正常。

    //创建图形以帮助hibernate使用外部联接创建查询。
    @NamedEntityGraph(name=“graph.Person.friends”,
    attributeNodes=@NamedAttributeNode(value=“friends”))
    类人{}
    接口PersonRepository扩展了JpaRepository{
    //使用命名图,它将获取同一查询中的所有好友
    @凌驾
    @EntityGraph(value=“graph.Person.friends”)
    完成人员(长id);
    }
    @凌驾
    公共人物addFriend(字符串personName、字符串friendName)
    抛出FriendsExistsException,PersonNotFoundException{
    Person-Person=retrieveWithName(personName);
    Person friend=retrieveWithName(friendName);
    如果(!person.getFriends().包含(friend)){
    person.getFriends().add(friend);
    friend.getFriends().add(person);//需要设置关系
    return repository.save(person);//只使用一种保存方法,它使用cascade保存好友
    }否则{
    抛出新的FriendsExistException(personName、friendName);
    }
    
    }

    如果查看hibernate日志,您将看到:
    休眠:在person(姓名、id)中插入值(?,)
    休眠:在person(姓名、id)中插入值(?,)
    Hibernate:在友谊(person\u id,friend\u id)中插入值(?,)

    Hibernate:插入友谊(person\u id,friend\u id)值(?,)

    您需要手动设置双向关系。比如
    friend.addFriend(person)和person.addFriend(friend)
    。如果你想处理这种关系,不如考虑一个图形数据库。我更喜欢在我的实体内创建一个助手方法,如
    makeFriendly(Person)
    ,并在那里设置关系,以使代码更可读。@BogdanOros我将以这种方式更新,但我不确定是否应该通过添加到彼此的好友列表来手动进行更新。这表明它是如何工作的。这样做是为了支持数据库中的关系,因为在关系数据库中,您需要有两行来指定此关系。@BogdanOros我知道这一点,并确切地询问这是否可行。我想用一个保存操作在友谊表中插入两行。您将调用
    save
    操作,因为您已经配置了级联,它将自动使用更新的友谊关系保留子集。这正好在以下行中给出stackoverflow错误:
    friend.getFriends()。add(person);
    尝试了相同的示例,没有stackoverflow错误,您可以粘贴stackstrace吗?我刚刚解决了stackoverflow错误。Lombok的toString()、equals()和hashCode()方法导致了它。我排除了friends元素,然后解决了它。现在我在获取一个人时遇到了一个问题。例如,当我获取Julia时,Michael在朋友列表上,它试图获取Michael的朋友列表,它给Julia带来了一个无限循环。这是N+1查询问题,我正在尝试解决它。是的,Lombok无法解析反向引用,这就是我使用DataClass等迁移到Kotlin的原因。对于我在上面提到的问题,您有什么解决建议吗?
        @Override
        public Person addFriend(String personName, String friendName) 
            throws FriendshipExistsException, PersonNotFoundException {
        Person person = retrieveWithName(personName);
        Person friend = retrieveWithName(friendName);
        if(!person.getFriends().contains(friend)){
            person.getFriends().add(friend);
            return repository.save(person);
        }
        else{
            throw new FriendshipExistsException(personName, friendName);
        }
    }
    
    // Creating a graph to help hibernate to create a query with outer join.
    @NamedEntityGraph(name="graph.Person.friends",
        attributeNodes = @NamedAttributeNode(value = "friends"))
    class Person {}
    
    interface PersonRepository extends JpaRepository<Person, Long> {
        // using the named graph, it will fetch all friends in same query
        @Override
        @EntityGraph(value="graph.Person.friends")
        Person findOne(Long id);
    }
    
    @Override
    public Person addFriend(String personName, String friendName) 
        throws FriendshipExistsException, PersonNotFoundException {
        Person person = retrieveWithName(personName);
        Person friend = retrieveWithName(friendName);
        if(!person.getFriends().contains(friend)){
            person.getFriends().add(friend);
            friend.getFriends().add(person); // need to setup the relation
            return repository.save(person); // only one save method is used, it saves friends with cascade
        } else {
            throw new FriendshipExistsException(personName, friendName);
        }