java 当循环引用是单个属性时,如何处理它?

ubof19bj  于 2023-03-21  发布在  Java
关注(0)|答案(1)|浏览(108)

我在一个Spring项目中,发现自己遇到了一个循环引用问题,与这里已经发布的问题有点不同(至少是我设法找到的问题)。

类结构

应用程序有一个用户类/实体。这个实体可以向其他用户发送“鸭子”。它与已经发送“鸭子”的用户有一个聚合关系(一个列表),另一个列表与已经向您发送“鸭子”的用户。(它是一个M-N基数关系)

@Entity
public class User{
    @ManyToMany
    @JsonManagedReference
    @JoinTable(
        name = "sendsDuck",
        joinColumns = @JoinColumn(name = "sender"),
        inverseJoinColumns = @JoinColumn(name = "receiver")
    )
    private Set<User> duckedUsers;

    @ManyToMany(mappedBy = "duckedUsers")
    @JsonBackReference
    private set <User> receivesDuckFrom;
    
    //Getters and setters
    ...

}

正如您所看到的,我添加了@JsonManagedReference@JsonBackReference标记,以精确地避免自引用或循环引用。

问题

问题是,当一个用户向另一个用户发送“duck”时,我上面提到的标记解决了循环引用问题。然而,当两个用户互相发送敏感的duck(A发送给B,B发送给A)时,我有一个循环引用,我不知道如何处理。
这是因为这两个对象在同一个duckedUsers属性中有另一个对象。

我都试过什么?

以下是我迄今为止所做的尝试,但没有成功:

  • @ JSON忽略

如果我把这个注解放在duckedUsers属性上,它可以正常工作。但是,API客户端需要知道它向其发送鸭子的用户的数据,所以这个解决方案不足以满足我的情况。

  • @JsonManagedReference和@JsonBackReference位于同一属性上

有点愚蠢的尝试,但是尝试在同一个属性上同时使用这两个注解,即使它们没有多大意义。

@ManyToMany
    @JsonManagedReference
    @JoinTable(
            name = "sendsDuck",
            joinColumns = @JoinColumn(name = "sender"),
            inverseJoinColumns = @JoinColumn(name = "receiver")
    )
  • 对象Map器

在控制器内部,尝试使用按以下方式配置的objectMapper:
一个二个一个一个
像这样使用它:

@PostMapping("/sendDuck")
    ResponseEntity sendDuck(@RequestParam Long transmitterId, @RequestParam Long receiverId) {
        User transmitter = this.findOrThrow(transmitterId);
        User receiver = this.findOrThrow(receiverId);
        transmitter.sendsDuck(receiver);
        repository.save(transmitter);
        repository.save(receiver);
        List<User> usersList = List.of(receiver, transmitter);
        CollectionModel<EntityModel<User>> body = this.collectionModelFromList(usersList);
        try{
            String serializedBody = objectMapper.writeValueAsString(body);
            return ResponseEntity.ok().body(body);
        }catch (IOException ex){
            String errorMessage = "JSON serializing error: " + ex.getMessage();
            return ResponseEntity.internalServerError().body(errorMessage);
        }
    }

这一尝试也没有成功。

我认为解决方案应该是什么样的?

从目前为止我所看到的,我明白我想要实现的是一个JSON响应,它的工作方式是只有当实体是响应中的子实体时才应用@JsonIgnore。类似这样:

{
   id:1,
   ...
   duckedUsers:[
      {
         id:1,
         ... 
         duckedUsers:... //This must NOT appear as is a child entity
      },
   ]
}
68de4m5k

68de4m5k1#

正如@Rogue在评论中解释的那样,更好的解决方案是将User实体和Ducks关系解耦。这是代码的结尾:
用户实体

@Entity
public class User{

    @OneToMany(mappedBy = "sender")
    private Set<Duck> ducksSent;

    @OneToMany(mappedBy = "receiver")
    private Set<Duck> ducksReceived;

    //Constructor, getters and setters....
}

鸭子实体

@Entity
public class Duck {
   
    @EmbeddedId
    private DuckId id;
    
    @ManyToOne
    @MapsId("senderId")
    private User sender;
    
    @ManyToOne
    @MapsId("receiverId")
    private User receiver;

    public Duck(User sender, User receiver) {
        this.sender = sender;
        this.receiver = receiver;
        this.id = new DuckId(sender.getId(),receiver.getId());
    }

    //getters and setters....
}

相关问题