gpt4 book ai didi

mysql - 当我更新多对多关系中的实体时,如何阻止 Hibernate/JPA 删除连接表记录?

转载 作者:行者123 更新时间:2023-12-03 08:36:44 24 4
gpt4 key购买 nike

我想更新实体而不更新/编辑子实体。这是有问题的实体:

@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;

//other fields omitted for brevity

@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "project_user",
joinColumns = @JoinColumn(name="user_id", updatable = false),
inverseJoinColumns = @JoinColumn(name="project_id",updatable = false))
@JsonIgnore
private Set<Project> projects;

//getters and setters omitted for brevity

@Override
public int hashCode() {
return id;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (id != other.id)
return false;
return true;
}

}

这是项目实体:

@Entity
@Table(name = "project")
public class Project {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;

//other fields omitted for brevity

@ManyToMany
@JoinTable(name = "project_user",
joinColumns = @JoinColumn(name="project_id"),
inverseJoinColumns = @JoinColumn(name="user_id"))
@JsonIgnoreProperties(value = {"projects", "connected", "notifications"})
private Set<User> members;

@Override
public int hashCode() {
return id;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Project other = (Project) obj;
if (id != other.getId())
return false;
return true;
}

}

这是合并过程:

@Override
public void update(User user) {
//user is created from a dto as a new object (that has its id set manually)
entityManager.merge(user);
}

问题是 hibernate 日志从连接表中删除。我怎样才能阻止它?

hibernate 日志

Hibernate: //login query
select
distinct authuser0_.id as id1_7_,
authuser0_.enabled as enabled8_7_,
authuser0_.password as password5_7_,
authuser0_.username as username6_7_,
roles1_.username as username1_0_0__,
roles1_.authority as authorit2_0_0__
from
users authuser0_
inner join
authorities roles1_
on authuser0_.username=roles1_.username
where
authuser0_.username=?
Hibernate: //entityManager.merge() calls this to merge it
select
user0_.id as id1_7_0_,
user0_.email as email2_7_0_,
user0_.first_name as first_na3_7_0_,
user0_.image as image7_7_0_,
user0_.last_name as last_nam4_7_0_,
user0_.password as password5_7_0_,
user0_.username as username6_7_0_
from
users user0_
where
user0_.id=?
Hibernate: //the actual update statement
update
users
set
email=?,
first_name=?,
image=?,
last_name=?,
password=?,
username=?
where
id=?
Hibernate: // not wanted, need to stop this query
delete
from
project_user
where
user_id=?

我在网上读到它与 equals 和 hashcode 有关。但是,我似乎无法让它发挥作用。

我知道两个选项都不是最佳的:

  1. 编写 native 查询而不是合并方法。问题:不可扩展,每次更改都需要手动编辑
  2. 为表创建一个新实体(因此该表将有 2 个映射到它的实体),而不附加到其他表。问题:重复的代码和实体

提前致谢

最佳答案

嗯,我知道您已经接受了答案,但是......

那里发生的事情比你想象的要多。

出现 Hibernate: delete from project_user where user_id=? 的原因是之后有插入。你没看到他们吗?如果该用户的关系表被清空但后来没有插入,那么关系可能没有更新?也只能重现删除操作,但您应该测试您的代码并验证该用户没有项目。这可能意味着您没有更新合并用户中的项目字段。

因此,运行一个基本的 JPA 示例,让我们从创建一个起点开始解决您的问题:

    em.getTransaction().begin();
Project project = new Project();
em.persist(project);
User user = new User();
Set<Project> projects = new HashSet<>();
projects.add(project);
user.setProjects(projects);
em.persist(user);
em.getTransaction().commit();

然后,清除entityManager上下文:

    em.clear();

然后重现您的问题:

    em.getTransaction().begin();
Project p2 = new Project();
em.persist(p2);
projects.add(p2);
User un = em.find(User.class, 1);
un.setProjects(projects);
em.merge(un);
em.getTransaction().commit();

第二部分给我日志:

Hibernate: insert into project (id) values (default)
Hibernate: select user0_.id as id1_2_0_ from users user0_ where user0_.id=?
Hibernate: select project0_.id as id1_0_0_ from project project0_ where project0_.id=?
Hibernate: delete from project_user where user_id=?
Hibernate: insert into project_user (user_id, project_id) values (?, ?)
Hibernate: insert into project_user (user_id, project_id) values (?, ?)

现在让我们通过更改代码并再次运行来删除有问题的 delete 语句:

    Project p2 = new Project();
em.persist(p2);
User un = em.find(User.class, 1);
projects = un.getProjects();
projects.add(p2);
em.merge(un);
em.getTransaction().commit();

这给了我日志:

Hibernate: insert into project (id) values (default)
Hibernate: select user0_.id as id1_2_0_ from users user0_ where user0_.id=?
Hibernate: select projects0_.user_id as user_id1_1_0_, projects0_.project_id as project_2_1_0_, project1_.id as id1_0_1_ from project_user projects0_ inner join project project1_ on projects0_.project_id=project1_.id where projects0_.user_id=?
Hibernate: insert into project_user (user_id, project_id) values (?, ?)

没有删除语句。仔细查看第一个“第二部分”,请注意我将新项目添加到了原始项目集中,该项目不再是 JPA 持久性上下文的一部分。在第二个示例中,我专门从属于 JPA 持久性上下文的 user 对象中检索了一组项目。现在,当我更新项目集并合并用户 JPA 时,不必重新开始处理用户/项目关系。

顺便说一句:就 mappedBy 逻辑而言,接受的答案是准确的,但此代码是根据您的原始示例完成的。只要 JPA 知道您在做什么,它就会正确处理它。当您在 JPA 之外执行操作时,JPA 将“下注”并重新创建。

关于mysql - 当我更新多对多关系中的实体时,如何阻止 Hibernate/JPA 删除连接表记录?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63690958/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com