Spring boot hibernate:不能单独删除子对象

Ant*_*met 2 java spring hibernate jpa

我有一个简单的设置有两个对象,EventTask其链接为父子和默认JPA库对于一些CRUD操作.我做了一个测试,我把2连接Task到一个Event,然后我尝试delete在其中一个上调用一个动作Task,它失败了(没有错误,也没有删除).

如果我运行相同的测试不添加TaskEvent,操作成功.我下面的所有代码,关于我接下来需要做什么的任何想法?

@Entity
public class Event {

    @Id
    @GeneratedValue(generator = "hibernate-uuid")
    @GenericGenerator(name = "hibernate-uuid", strategy = "uuid2")
    @Column(unique = true)
    String id;

    String subject;

    @OneToMany(mappedBy="event", cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
    @JsonIgnoreProperties({"event"})
    List<Task> tasks;
}

@Entity
public class Task {
    @Id
    @GeneratedValue(generator = "hibernate-uuid")
    @GenericGenerator(name = "hibernate-uuid", strategy = "uuid2")
    @Column(unique = true)
    String id;

    String subject;

    @ManyToOne
    @JsonIgnoreProperties({"tasks"})
    Event event;
}

public interface TaskRepository extends JpaRepository<Task, String> {
    public Task findById(String id);
}
Run Code Online (Sandbox Code Playgroud)

而且测试:

@Test
public void testSequenceOfActionsOnEventWithSubtasks() {
    // Save a new task
    Task savedTask = given()
            .body(
                    new TaskBuilder()
                            .subject("Previously saved task")
                            .build()
            ).contentType(ContentType.JSON)
            .when().post(TASKS_RESOURCE).as(Task.class);


    Task unsavedTask = new TaskBuilder()
            .subject("Unsaved task")
            .build();


    // Save a new event with an unsaved and a saved task attached
    Event savedEvent = given()
            .body(
                    new EventBuilder()
                            .subject("Main event")
                            .addTask(savedTask)
                            .addTask(unsavedTask)
                            .build()
            ).contentType(ContentType.JSON)
            .when().post(EVENTS_RESOURCE).as(Event.class);


    // Make sure the event now contains two tasks with GUID's attached
    List<Task> tasksForEvent = when().get(EVENT_RESOURCE, savedEvent.getId()).as(Event.class).getTasks();
    assertEquals(2, tasksForEvent.size());

    // Get all tasks, make sure firstTask is in there
    when().get(TASKS_RESOURCE).then().body(SUBJECT_FIELD, hasItems(savedTask.getSubject()));

    // Delete a task that was attached to the event
    when().delete(TASK_RESOURCE, savedTask.getId()).then().statusCode(HttpStatus.SC_OK);

    // Get all tasks, make sure firstTask is NOT in there
    when().get(TASKS_RESOURCE).then().body(SUBJECT_FIELD, not(hasItems(savedTask.getSubject())));

    // Check the event again
    tasksForEvent = when().get(EVENT_RESOURCE, savedEvent.getId()).as(Event.class).getTasks();
    assertEquals(1, tasksForEvent.size());
}
Run Code Online (Sandbox Code Playgroud)

更新:如果我删除fetch = FetchType.EAGER@OneToMany在上Event类,它的工作原理.虽然知道原因仍然很好.以下是我的新Event课程.

@Entity
public class Event {

    @Id
    @GeneratedValue(generator = "hibernate-uuid")
    @GenericGenerator(name = "hibernate-uuid", strategy = "uuid2")
    @Column(unique = true)
    String id;

    String subject;

    @OneToMany(mappedBy="event", cascade = { CascadeType.ALL })
    @JsonIgnoreProperties({"event"})
    List<Task> tasks;
}
Run Code Online (Sandbox Code Playgroud)

Dra*_*vic 5

JPA规范的相关摘录:

3.2.4节:

应用于实体X的刷新操作的语义如下:

  • 如果X是托管实体,则会将其同步到数据库.
    • 对于来自X的关系引用的所有实体Y,如果与Y的关系已使用级联元素值cascade = PERSIST或cascade = ALL进行注释,则将持久化操作应用于Y

3.2.2节:

应用于实体X的持久化操作的语义如下:

  • 如果X是已删除的实体,则它将被管理.

那么,你的情况是怎么回事:

  1. 你删除了一个Task.
  2. 在事务结束时,Hibernate将持久化上下文与数据库同步.
  3. 它找到了Event实例.没有变化,但PERSIST操作级联到tasks.
  4. PERSIST应用于集合Task中的所有s tasks,包括已删除的s ,它将再次被管理.

要验证这一点,请启用包的TRACE日志级别org.hibernate并搜索包含的邮件un-scheduling entity deletion.

如果tasks是懒惰加载,PERSIST则不应用于它们(如果集合在此期间没有初始化,当然); 这就是为什么在这种情况下你没有看到这种行为的原因.

解决的办法是删除从已删除任务Eventtasks集合也使PERSIST不适用于它.