我正在开发REST类型的Web应用程序,其中前端使用Angular(Typescript),后端使用Spring(引导,休息,数据,休眠)连接到MySQL数据库。 在此应用程序中,用户java对象具有属性,并使用JPA注释链接到对象的几个列表(出版物,预期用途,角色,userGroups和managedGroups),如下所示。
在User.java
中@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name = "userId")
private Long userId;
private String firstName;
private String lastName;
private String email;
private String photo;
private String instantMessaging;
@Column(length = 50)
private String phoneNumber;
private String personnalURL;
private Timestamp charterAcceptanceDate;
@Column(unique=true)
private String username;
private Timestamp expirationDate;
private String password;
private Timestamp creationDate;
private Timestamp approvedDate;
private boolean isActive;
private boolean isAdmin;
// Relations
@OneToMany(mappedBy = "user", cascade = CascadeType.MERGE, orphanRemoval = true)
private List<Publication> publications = new ArrayList<>();
@OneToMany(mappedBy = "user", cascade = CascadeType.MERGE, orphanRemoval = true)
private List<IntendedUsage> intendedUsages = new ArrayList<>();
@ManyToMany(cascade = CascadeType.MERGE, fetch=FetchType.EAGER)
private List<Role> roles = new ArrayList<>();
// List of groups the user belongs to.
@ManyToMany(cascade = {CascadeType.MERGE}, fetch = FetchType.LAZY)
@JoinTable(
name = "user_group",
joinColumns = { @JoinColumn(name = "user_id") },
inverseJoinColumns = { @JoinColumn(name = "group_id") }
)
private List<Group> userGroups = new ArrayList<>();
// List of groups managed by the user.
@ManyToMany(cascade = {CascadeType.MERGE}, fetch = FetchType.LAZY)
@JoinTable(
name = "managed_group",
joinColumns = { @JoinColumn(name = "user_id") },
inverseJoinColumns = { @JoinColumn(name = "group_id") }
)
private List<Group> managedGroups = new ArrayList<>();
In Role.java
@JsonSerialize(using = UserListCustomSerializer.class)
@ManyToMany(mappedBy = "roles")
private List<User> users = new ArrayList<>();
In Group.java
// List of users included in the group.
@JsonSerialize(using = UserListForGroupCustomSerializer.class)
@ManyToMany(mappedBy = "userGroups")
private List<User> users = new ArrayList<>();
// List of users who are managing the group.
@JsonSerialize(using = ManagerListForGroupCustomSerializer.class)
@ManyToMany(mappedBy = "managedGroups")
private List<User> managerUsers = new ArrayList<>();
在前端,我有一个修改用户特征的表格。当我提交修改时,前端将这样的JSON文件发送到后端:
{
"active":true,
"admin":false,
"approvedDate":"1970-01-01T23:47:13.000+0000",
"charterAcceptanceDate":"1970-01-09T18:44:13.000+0000",
"creationDate":"1970-01-02T10:49:26.000+0000",
"email":"jack.bauer@gmake.com",
"expirationDate":"1970-01-02T10:49:26.000+0000",
"firstName":"Jack",
"instantMessaging":"skype.com",
"lastName":"Bauer",
"login":"","password":"",
"personnalURL":"http://www.jack.com",
"phoneNumber":"0686596352",
"photo":"/home/jjj/",
"userId":1,
"username":"jbauerooooo"
}
没有关于用户出版物,预期用途,角色,用户组和托管组的信息,这是正常的。 在这里,我只想修改用户的一般特征,而不是他的列表。
我认为,对于CascadeType.MERGE,如果没有与用户链接的列表有关的信息,则现有列表(记录在数据库中)将保留在数据库中。
对于一对多关系确实如此,但对于一对多关系则不是。前端发送上述JSON文件时,将删除数据库中角色,userGroups,managedGroups的当前数据记录。
为什么? 如何避免这种情况?
我尝试使用CascadeType.ALL,在这种情况下,所有与列表有关的数据均被删除。 我对ManyToMany关系尝试了CascadeType的所有值。这是同样的问题。
预先感谢您的回答...
答案 0 :(得分:0)
合并不会执行您认为的操作。它相当复杂,我无法解释它的作用,但是您可以查阅并找到一些不错的文章。当您发送该json数据时,它会被序列化,即使您没有将其包含在json文件中,java也会将not included字段设置为null。当您保存实体时,休眠将删除子级或将字段设置为空(因为在Java中,它们为空)。为了实现您的目标,我将在您的实体上使用@DynamicUpdate批注。然后,您可以创建一个表示您的部分json数据的DTO。然后在您的服务中按ID提取实体,并从DTO设置其相关字段。延迟加载将确保不会从数据库中拉出子级,而@DynamicUpdate将确保仅将更新的字段包含在来自休眠的更新SQL语句中。这应该是相当有效的。我还建议您将属性中的hibernate.show_sql标志设置为true,以便您可以看到hibernate在做什么。 Hibernate可以做一些时髦的事情,甚至有时会忽略您的注释。