我有一个简单的设置,包含两个对象,Event
和 Task
,它们作为父子链接,以及用于某些 CRUD 操作的默认 JPA 存储库。我做了一个测试,我将 2 个 Task
附加到一个 Event
,然后我尝试对其中一个 调用一个
,失败(没有错误,也没有删除)。 delete
操作>Task
如果我在未将 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());
}
更新:如果我从 Event
类的 @OneToMany
中删除 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;
}
最佳答案
相关摘录自JPA specification :
3.2.4部分:
The semantics of the flush operation, applied to an entity X are as follows:
- If X is a managed entity, it is synchronized to the database.
- For all entities Y referenced by a relationship from X, if the relationship to Y has been annotated with the cascade element value cascade=PERSIST or cascade=ALL, the persist operation is applied to Y
3.2.2部分:
The semantics of the persist operation, applied to an entity X are as follows:
- If X is a removed entity, it becomes managed.
那么,你的情况是怎样的:
- 您删除了一个
任务
。 - 在事务结束时,Hibernate 将持久化上下文与数据库同步。
- 它找到
Event
实例。它没有变化,但PERSIST
操作级联到tasks
。 PERSIST
应用于tasks
集合中的所有Task
,包括已删除的,它再次被管理。
要验证这一点,请为 org.hibernate
包启用 TRACE
日志级别,并搜索包含 un-scheduling entity deletion
的消息。
如果延迟加载任务
,则不会将PERSIST
应用于它们(当然,如果同时未初始化集合);这就是为什么在这种情况下您看不到这种行为的原因。
解决方案是从 Event
的 tasks
集合中删除已删除的任务,这样 PERSIST
就不会应用于它。
关于java - Spring 启动 hibernate : cannot delete child object separately,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33409972/