如何在 Spring Boot 中更新子实体和父实体?
Posted
技术标签:
【中文标题】如何在 Spring Boot 中更新子实体和父实体?【英文标题】:How to update Child entity along with Parent entity in Spring Boot? 【发布时间】:2021-03-12 22:37:16 【问题描述】:我正在尝试使用 JPA 更新父实体和子实体(与父实体一起提供)。我尝试了很多方法,但我做不到。它给了我以下错误。
javax.persistence.EntityExistsException: 一个不同的对象 相同的标识符值已与会话 Contact(6) 相关联
下面是实体,
父 -> 用户.java
@Entity
public class User extends Serializable
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_generator")
@SequenceGenerator(name = "seq_generator", sequenceName = "seq_users", initialValue = 1, allocationSize = 1)
private Long id;
private String firstName;
private String lastName;
private String email;
private String password;
private String street;
private String city;
@OneToOne(cascade = CascadeType.ALL, mappedBy = "userContact")
private Contact contact;
孩子 -> Contact.java
@Entity
public class Contact extends Serializable
private static final long serialVersionUID = 1L;
@Getter(value = AccessLevel.NONE)
@Setter(value = AccessLevel.NONE)
@Id
@Column(insertable = false, updatable = false)
private Long id;
@MapsId
@OneToOne
@JoinColumn(name = "id", nullable = false)
private User userContact;
private String phone;
在我的 Service.java 中我是这样更新的,
@Override
@Transactional
public User update(Long id, User user)
Optional<User> curUser = userRepo.findById(id);
user.setId(curUser.get().getId());
user.setStreet(curUser.get().getStreet());
user.setCity(curUser.get().getCity());
Contact contact = user.getContact();
contact.setUserContact(user);
user.setContact(contact);
return userRepo.save(user);
而更新JSON的payload是这样的,
"firstName": "FirstName",
"lastName": "LastName",
"email": "Email",
"password": "Password",
"contact":
"phone": "0123456789"
那么为什么我不能立即更新呢?插入工作正常,但此更新不起作用。我在这里做错了什么?如果有人可以帮助我,我真的很感激。提前致谢。
这是我尝试的新方法,
@Override
@Transactional
public User update(Long id, User user)
Optional<User> curUser = userRepo.findById(id);
curUser.setFirstName(user.getFirstName());
curUser.setlastName(user.getLastName());
curUser.setEmail(user.getEmail());
curUser.setPassword(user.getPassword());
Contact contact = user.getContact();
contact.setUserContact(curUser);
curUser.setContact(contact);
return userRepo.save(curUser);
【问题讨论】:
如果您有用户和联系人的存储库,请先尝试将联系人保存在联系人存储库中。如果这种方法对您有帮助,请告诉我 @jafarmlp 我试过了,但还是一样的错误。 【参考方案1】:因为您在持久化上下文中有两次表示相同的用户(即相同的 id)。
这一行在持久化上下文中加载用户curUser
。
Optional<User> curUser = userRepo.findById(id);
这一行使user
的 id 是同一个用户,但它是一个不同的瞬间。
user.setId(curUser.get().getId());
最后这一行尝试将user
添加到持久化上下文中。
userRepo.save(user);
这将导致两个实例附加到持久性上下文,同时代表具有相同 id 的同一用户,这将导致状态不一致,因为 JPA 不知道要持久化哪个版本。因此这是禁止的,并会引发您所看到的异常。
在你的情况下改变
Optional<User> curUser = userRepo.findById(id);
user.setId(curUser.get().getId());
到
user.setId(id);
应该可以解决问题。
关于你的 cmets:
引用对象也存在同样的问题。您必须确保:加载实体并更改其属性,或者不加载实体,不直接或间接通过引用并保存根据您的请求构造的分离实体。
如果您加载一个实体,然后尝试保存它的分离实例,您将收到此类错误。
【讨论】:
非常感谢您的回答和您的时间。我能够修复它。以上是关于如何在 Spring Boot 中更新子实体和父实体?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Spring Boot 应用程序中将 java lang long 转换为实体类