英文:
Hibernate - there is a way of deleting child by id with orphanremoval = true?
问题
下面是翻译好的内容:
子实体:
package com.yoav.todolist.models;
import com.fasterxml.jackson.annotation.JsonIgnore;
import javax.persistence.*;
import java.util.Date;
@Entity
@Table(name = "tasks")
public class Task {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "task")
private String task;
@ManyToOne(fetch = FetchType.LAZY)
@JsonIgnore
private Account account;
@Temporal(TemporalType.DATE)
@Column(name = "date_of_creation_task")
private Date date;
// ... 其他方法和属性
}
父实体:
package com.yoav.todolist.models;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "accounts")
public class Account {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "username")
private String username;
@Column(name = "password")
private String password;
@OneToMany(
mappedBy = "account",
orphanRemoval = true,
cascade = CascadeType.ALL
)
private List<Task> tasks = new ArrayList<>();
// ... 其他方法和属性
}
删除方法:
@Query(value = "DELETE FROM tasks WHERE tasks.id = ?1", nativeQuery = true)
@Transactional
@Modifying
@Override
void deleteById(int id);
测试:
Account account = new Account("person", "person");
account.addTask(new Task("java"));
account.addTask(new Task("spring"));
accountDao.add(account);
MockHttpSession session = new MockHttpSession();
session.setAttribute("isAdmin", true);
System.out.println(accountDao.findByUsername("person").orElse(new Account()).getTasks());
assertThat(accountDao.findByUsername("person").orElse(new Account()).getTasks()).hasSize(2);
mockMvc.perform(post("/admin/person").session(session)
.param("deleteTask",
String.valueOf(accountDao
.findByUsername("person").orElse(new Account()).getTasks().get(0).getId())))
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl("/admin/person"));
System.out.println(accountDao.findByUsername("person").orElse(new Account()).getTasks());
System.out.println(taskDao.getAll());
assertThat(accountDao.findByUsername("person").orElse(new Account()).getTasks()).hasSize(1);
控制器:
@RequestMapping(value = "/admin/{usernameOfAccount}", method = RequestMethod.POST, params = "deleteTask")
public String postDeleteTasksOfUsername(
@RequestParam String deleteTask,
@PathVariable String usernameOfAccount,
HttpSession session) {
if (session.getAttribute("isAdmin") == null) return "unauthorized";
int idOfDeletingTask = Integer.parseInt(deleteTask);
taskService.deleteById(idOfDeletingTask);
return "redirect:/admin/" + usernameOfAccount;
}
以上是你提供的代码的翻译。如果你有其他问题或需要进一步帮助,请随时提问。
英文:
I am trying to delete a child entity by id in many to one relationship with spring-data-jpa but when I try to look at the child's from the parent perspective its still there but its not in the actual database
the child entity:
package com.yoav.todolist.models;
import com.fasterxml.jackson.annotation.JsonIgnore;
import javax.persistence.*;
import java.util.Date;
@Entity
@Table(name = "tasks")
public class Task {
@Id
@Column(name = "id")
@GeneratedValue(strategy= GenerationType.IDENTITY)
private int id;
@Column(name = "task")
private String task;
@ManyToOne(fetch = FetchType.LAZY)
@JsonIgnore
private Account account;
@Temporal(TemporalType.DATE)
@Column(name = "date_of_creation_task")
private Date date;
public Task(String task) {
this.date = new Date();
this.task = task;
}
public Task() {
this.date = new Date();
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTask() {
return task;
}
public void setTask(String task) {
this.task = task;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
@Override
public boolean equals(Object task) {
return ((Task)task).getId() == this.id;
}
@Override
public String toString() {
return "Task{" +
"id=" + id +
", task='" + task + '\'' +
'}';
}
@Override
public int hashCode() {
return 31;
}
}
the parent entity:
package com.yoav.todolist.models;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "accounts")
public class Account {
@Id
@Column(name = "id")
@GeneratedValue(strategy= GenerationType.IDENTITY)
private int id;
@Column(name = "username")
private String username;
@Column(name = "password")
private String password;
@OneToMany(
mappedBy = "account",
orphanRemoval = true,
cascade = CascadeType.ALL
)
private List<Task> tasks = new ArrayList<>();
public Account(String username, String password) {
this.username = username;
this.password = password;
}
public Account() {
}
public void removeTask(Task task) {
tasks.remove(task);
task.setAccount(null);
}
public void addTask(Task task) {
tasks.add(task);
task.setAccount(this);
}
public List<Task> getTasks() {
return tasks;
}
public void setTasks(List<Task> tasks) {
this.tasks.forEach(i -> i.setAccount(null));
this.tasks.clear();
tasks.forEach(i -> {
i.setAccount(this);
addTask(i);
});
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public boolean equals(Object account) {
return ((Account)account).getUsername().equals(this.username);
}
@Override
public String toString() {
return "Account{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
the delete by id method: (in the JpaRepository)
@Query(value = "DELETE FROM tasks WHERE tasks.id = ?1", nativeQuery = true)
@Transactional
@Modifying
@Override
void deleteById(int id);
the test(that prove my problem):
Account account = new Account("person", "person");
account.addTask(new Task("java"));
account.addTask(new Task("spring"));
accountDao.add(account);
MockHttpSession session = new MockHttpSession();
session.setAttribute("isAdmin", true);
System.out.println(accountDao.findByUsername("person").orElse(new Account()).getTasks());
assertThat(accountDao.findByUsername("person").orElse(new Account()).getTasks()).hasSize(2);
mockMvc.
perform(post("/admin/person").session(session).
param(
"deleteTask",
String.valueOf(accountDao.
findByUsername("person").orElse(new Account()).getTasks().get(0).getId())
)).
andExpect(status().is3xxRedirection()).
andExpect(redirectedUrl("/admin/person"));
// here is the main problem here I get the both child's
// account.addTask(new Task("java"));
// account.addTask(new Task("spring"));
System.out.println(accountDao.findByUsername("person").orElse(new Account()).getTasks());
// but here i get only one child and i dont see the child that i removed
System.out.println(taskDao.getAll());
assertThat(accountDao.findByUsername("person").orElse(new Account()).getTasks()).hasSize(1);
the controller:
@RequestMapping(value = "/admin/{usernameOfAccount}", method = RequestMethod.POST, params = "deleteTask")
public String postDeleteTasksOfUsername(
@RequestParam String deleteTask,
@PathVariable String usernameOfAccount,
HttpSession session) {
if (session.getAttribute("isAdmin") == null) return "unauthorized";
int idOfDeletingTask = Integer.parseInt(deleteTask);
taskService.deleteById(idOfDeletingTask);
return "redirect:/admin/" + usernameOfAccount; // redirecting back to the list of tasks of the specifying username
}
答案1
得分: 1
// 这里是主要的问题,我在这里得到了两个子节点
// account.addTask(new Task("java"));
// account.addTask(new Task("spring"));
System.out.println(accountDao.findByUsername("person").orElse(new Account()).getTasks());
你的测试事务性吗?
如果是的话,那么在这里返回的 Account 对象已经加载到持久化上下文中,所以你得到的是你之前调用 accountDao.findByUsername("person") 时得到的**完全相同的实例**,这也是你之前使用 accountDao.add(account) 进行持久化的**完全相同的实例**。
尝试在测试中注入 EntityManager,并在删除任务后立即调用 entityManager.flush(),然后紧接着调用 entityManager.clear()。
英文:
// here is the main problem here I get the both child's
// account.addTask(new Task("java"));
// account.addTask(new Task("spring"));
System.out.println(accountDao.findByUsername("person").orElse(new Account()).getTasks());
Is your test transactional?
If so, then the Account
that is being returned here is already loaded into the persistence context, so you're getting the exact same instance you got from the previous calls to accountDao.findByUsername("person")
, which is also the exact same instance you persisted using accountDao.add(account)
earlier on.
Try injecting EntityManager
into your test and calling entityManager.flush()
followed by entityManager.clear()
right after deleting the task.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论