2015-10-29 55 views
2

我有一個簡單的設置與兩個對象,EventTask作爲父子和鏈接和一些CRUD操作的默認JPA存儲庫。我做了一個測試,我在其中附加了2 Task s到Event,然後我嘗試對這些Task s之一調用delete操作,該操作失敗(沒有錯誤,也沒有刪除)。春季引導休眠:無法單獨刪除子對象

如果我運行相同的測試,但不將Task添加到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 }, 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); 
} 

而且測試:

@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()); 
} 

更新:如果我從@OneToMany上的Event類中刪除fetch = FetchType.EAGER,它的工作原理。但仍然很高興知道爲什麼。以下是我的新課程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; 
} 

回答

4

相關摘錄:

3.2.4

刷新操作的語義,施加到一個實體X如下面的 :

  • 如果X是一個託管實體,它將同步到數據庫。
    • 對於由從X的關係中引用的所有實體Y,如果Y的關係已經被註釋與級聯元件值 級聯=持續或級聯= ALL,persist操作被施加於Y

3.2.2

的持續操作的語義,應用於實體X如下 :

  • 如果X是一個被刪除的實體,它將被管理。

那麼,這是怎麼回事,你的情況:

  1. 您刪除Task
  2. 在事務結束時,Hibernate將持久化上下文與數據庫進行同步。
  3. 它找到了Event實例。它沒有變化,但PERSIST操作被級聯到tasks
  4. PERSIST適用於tasks集合中的所有Task s,包括已刪除的一個,這會再次進行管理。

爲了驗證這一點,啓用org.hibernateTRACE日誌級別和搜索包含un-scheduling entity deletion消息。

如果tasks延遲加載,那麼PERSIST不適用於它們(當然,如果集合未在其間初始化);這就是爲什麼你沒有看到這種情況下的行爲。

解決方法是從Eventtasks集合中刪除已刪除的任務,以便PERSIST不適用於它。

1

加orphanRemoval = true屬性從JPA specification

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