将级联类型删除应用于多对多关系

Apply cascade type delete to many to many relation

我目前正在开发一个网络票务系统,并且 类 可以存储我的票务数据。每张票都可以关联多个标签,为了管理这些标签,我创建了一个标签编辑器。这很好用,只是缺少删除选项。到目前为止,大多数删除都失败了,并解释说该标签仍被另一张票引用,这需要先将其删除。在寻找解决方案的过程中,我遇到了 CascadeType.DELETE,这似乎正是我所追求的。

但是,由于工单对象包含一组标签而不是反过来,所以每次我删除工单时,所有标签都会消失,而不是相反。在阅读了 CascadeType 的文档之后,这似乎是显而易见的,但我现在对如何实现相反的效果一无所知。我想创建一个对所有使用我的标签的票的引用,尽管这似乎将相同的数据存储了两次。

我的票看起来像这样:


@Entity
@Data
@NoArgsConstructor
public class Ticket {
    @Id
    @Column(length = 40)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @Column(nullable = false)
    private String title;

    @OneToMany(targetEntity = TicketEntry.class, mappedBy = "ticket", orphanRemoval = true, fetch = FetchType.EAGER)
    private List<TicketEntry> entries = new ArrayList<>();

    @Column
    private Status status = Status.OPEN;

    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "ticket_labels",
            joinColumns = { @JoinColumn(name = "ticket_id")},
            inverseJoinColumns = { @JoinColumn(name = "label_id" )}
    )
    private Set<TicketLabel> labels = new HashSet<>();
}

还有这样的标签:

@Entity
@Data
@NoArgsConstructor
public class TicketLabel {

    @Id
    @Column(length = 40)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    private String name = "";

    @EqualsAndHashCode.Exclude
    @ToString.Exclude
    @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.REMOVE)
    @JoinTable(name = "ticket",
            joinColumns = { @JoinColumn(name = "label_id")},
            inverseJoinColumns = { @JoinColumn(name = "ticket_id" )}
    )
    private Set<Ticket> tickets = new HashSet<>();
}

但这仍然不起作用。我什至需要在我的 Label 对象中引用我的所有 Tickets 吗?或者我能以某种方式使用“反向删除”级联类型吗?

您的 many-to-many 映射意味着您有两个交集表 ticket 和 ticket_labels。我打赌你不想要那个,你只需要一个。对于双向映射,您可能有:

public class TicketLabel {
//...
   @ManyToMany(mappedBy = "labels", cascade {CascadeType.MERGE, CascadeType.PERSIST})
   private Set<Ticket> tickets = new HashSet<>();
}
//...

public class Ticket {
// ...
   @ManyToMany
   @JoinTable(name = "ticket_labels",
       joinColumns = { @JoinColumn(name = "ticket_id")},
       inverseJoinColumns = { @JoinColumn(name = "label_id" )}
   )
   private Set<TicketLabel> labels = new HashSet<>();

   public void removeLabel(Label label) {
      labels.remove(label);
      label.getTickets().remove(this);
   }

   public void addLabel(Label label) {
      labels.add(label);
      label.getTickets().add(this);
   }
// ...
}

您必须按照 中所述,通过帮助删除和添加方法手动同步标签和票证。要移除标签,您必须将其从所有门票中移除。 CascadeType.REMOVE 在这种情况下会导致删除整个关联。