在@ManyToMany 关系中更新后休眠不需要的/意外的删除语句

Hibernate unwanted / unexpected delete statement after update in @ManyToMany relationship

我将提供一些关于我的 webapp 的一般信息(我现在只提及有问题的 tables)。所以,我有 3 tables Trainer、Event 和 Event-Trainer。

CREATE TABLE `Event` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `Title` varchar(1000) DEFAULT NULL,
  `Date` varchar(45) DEFAULT NULL,
  `Time` varchar(45) DEFAULT NULL,
  `Duration` varchar(20) DEFAULT NULL,
  `Location` varchar(45) DEFAULT NULL,
  `Days` int(11) DEFAULT '1',
  `Price` double DEFAULT NULL,
  `PlaceLimit` int(11) DEFAULT NULL,
  `CategoryID` int(11) DEFAULT NULL,
  `Notes` varchar(1000) DEFAULT '(No notes)',
  PRIMARY KEY (`ID`),
  KEY `CategoryID_idx` (`CategoryID`),
  CONSTRAINT `CategoryID` FOREIGN KEY (`CategoryID`) REFERENCES `Category` (`ID`) ON DELETE NO ACTION ON UPDATE NO ACTION
)

CREATE TABLE `Trainer` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `FirstName` varchar(45) DEFAULT NULL,
  `LastName` varchar(45) DEFAULT NULL,
  `Email` varchar(45) DEFAULT NULL,
  `Phone` varchar(45) DEFAULT NULL,
  `City` varchar(45) DEFAULT NULL,
  `Picture` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`ID`)
) 
CREATE TABLE `Event-Trainer` (
  `EventID` int(11) NOT NULL,
  `TrainerID` int(11) NOT NULL,
  PRIMARY KEY (`EventID`,`TrainerID`),
  KEY `FK_TrainerID` (`TrainerID`),
  CONSTRAINT `FK_EventID_2` FOREIGN KEY (`EventID`) REFERENCES `Event` (`ID`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `FK_TrainerID_2` FOREIGN KEY (`TrainerID`) REFERENCES `Trainer` (`ID`) ON DELETE NO ACTION ON UPDATE NO ACTION
)

这些是实体 类

//Event.java
@Entity
@Table(name = "Event", schema = "business-club")
public class Event {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID")
    private int id;

    ...    

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "CategoryID")
    private Category category;



    @ManyToMany(cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}
            , fetch = FetchType.EAGER)
    @JoinTable(
            name = "`Event-Trainer`",
            joinColumns = @JoinColumn(name = "EventID"),
            inverseJoinColumns = @JoinColumn(name = "TrainerID")
    )
    private List<Trainer> trainers;
...
}

//Trainer.java
    @Entity
@Table(name = "Trainer", uniqueConstraints = {@UniqueConstraint(columnNames = {"FirstName","LastName","Email"})})
public class Trainer {

    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    @Column(name="ID")
    private int id;

    ...

    @ManyToMany(cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
    @JoinTable(
            name="`Event-Trainer`",
            joinColumns = @JoinColumn(name = "TrainerID"),
            inverseJoinColumns = @JoinColumn (name="EventID")
    )
    private List<Event> events;

现在让我们开始讨论这个问题,我在使用 Hibernate 时遇到了一个奇怪的行为,即在我更新一个 Trainer 之后它 "Unexpectedly" 删除了 Event-Trainer 中与该培训师相关的记录 table 这是我更新训练器后休眠的日志

Hibernate: update Trainer set City=?, Email=?, FirstName=?, LastName=?, Phone=?, Picture=?  where ID=?
Hibernate: delete from `Event-Trainer` where TrainerID=?

我尝试更改两个实体中的级联类型但它没有用,我将获取类型更改为 LAZY 并且在更新时出现异常(如果有人向我解释这个我将不胜感激,尽管我不不认为这有什么大不了的,至少现在是这样)

如果需要,我会post更多信息

我认为 CascadeType.DETACH 超过 table 'Event-Trainer' 导致了这个问题。 您能在 'Trainer' table 中看到更新后的值吗?

多对多关系的映射不正确。您应该使用 @ManyToMany 中的 mappedBy 属性使一侧为主,另一侧为从。

感谢 Mohamed Gara,这是我的问题的解决方案 我改变了

//Trainer Entity
    @ManyToMany(cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
    @JoinTable(
            name="`Event-Trainer`",
            joinColumns = @JoinColumn(name = "TrainerID"),
            inverseJoinColumns = @JoinColumn (name="EventID")
    )
    private List<Event> events;

@ManyToMany(mappedBy = "trainers",fetch = FetchType.EAGER)
private List<Event> events;

//Event Entity
    @ManyToMany(cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH}
            , fetch = FetchType.EAGER)
    @JoinTable(
            name = "`Event-Trainer`",
            joinColumns = @JoinColumn(name = "EventID"),
            inverseJoinColumns = @JoinColumn(name = "TrainerID")
    )
    private List<Trainer> trainers;

@ManyToMany(fetch = FetchType.EAGER)
private List<Trainer> trainers;

我还必须将 table Event-Trainer 的名称更改为 Event_Trainer 并将主键的名称从 EventID、TrainerID 更改为 events_ID、trainers_ID 分别。 (我在抛出一些异常后这样做了)

编辑 1

我在删除分配给事件的培训师时遇到异常,因此我将两个外键的删除和更新时从 NO ACTION 更改为 CASCADE,并在两个实体的 @ManyToMany 注释中指定了级联类型

@ManyToMany( ... cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})