gpt4 book ai didi

java - JPA 多对一关系 CascadeType 行为

转载 作者:行者123 更新时间:2023-12-01 10:01:47 24 4
gpt4 key购买 nike

我有 2 个表:UserLoan。用户有 3 个字段:id (PK)、first_namelast_nameLoan 表的字段 user_idUser 表的外键: enter image description here

我的应用程序的逻辑:当我创建新的 Loan 对象并设置相应的 user 时,它应该为唯一用户创建一个新对象或设置一个 用户的id转换为现有用户的user_id

为此,我的数据库在 first_namelast_name 上有一个唯一索引。

Loan 类使用 User@ManyToOne 关系:

public class Loan {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name = "user_id")
private User user;
... methods ...

当我添加新用户时,一切都很好,它会以新的 PK 持久保存到数据库。但是当我尝试添加现有的一个时,我遇到了异常:

javax.servlet.ServletException: org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.0.v20150309-bf26070): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLIntegrityConstraintViolationException: The statement was aborted because it would have caused a duplicate key value in a unique or primary key constraint or unique index identified by 'FIRST_LAST_NAME' defined on 'USER'.
Error Code: 20000

再次,当我输入 @ManyToOne(cascade = CascadeType.MERGE) 时,我只能输入现有用户,因为只有我传递一个未保留在数据库中的新用户时,我遇到了异常:

javax.servlet.ServletException: org.springframework.dao.InvalidDataAccessApiUsageException: During synchronization a new object was found through a relationship that was not marked cascade PERSIST: User{id=null, firstName='a', lastName='a'}.;

@ManyToOne(cascade = CascadeType.ALL) 效果不佳。

更新

插入新Loan的代码是:

user = userService.findByName(firstName, lastName);
if (user == null) {
user = new User(firstName, lastName);
}
loan.setUser(user);
loanService.save(loan);

findByName()save() 方法是:

private EntityManager em;    
public User findByName(String firstName, String lastName) {
TypedQuery<User> query = em.createQuery(
"SELECT u FROM User u WHERE u.firstName = :firstName " +
"AND u.lastName = :lastName", User.class)
.setParameter("firstName", firstName).setParameter("lastName", lastName);
List<User> users = query.getResultList();
if (!users.isEmpty()) {
return users.iterator().next();
} else {
return null;
}
}

public void save(User user) {
if (user.getId() == null) {
em.persist(user);
} else {
em.merge(user);
}
}

最佳答案

如果您调用坚持贷款a) 在用户关系上设置了cascade.Persist并且引用的用户存在,如果没有从同一个EntityManager实例/上下文读入用户实例,您将得到一个异常 - 您正在通过userService读取它,然后保存贷款在贷款服务中,因此上下文必须由容器管理并在同一事务中才能工作。

b) 如果未设置cascade.PERSIST(或cascade.ALL)并且引用用户是新的,您将收到“找到新对象”异常。

如果您无法在要保存贷款的同一个 EntityManager 中执行用户读取,则切换到使用合并可能会有所帮助,因为 JPA 随后应检查引用的实体并根据需要进行合并。然后,您需要在关系上设置cascade.MERGE 选项,以便将合并应用到User 实例。

请注意,使用合并与持久不同,因为您传入的内容不会由上下文管理。这意味着事务提交后,传入的实体仍然没有设置任何主键值。如果您要继续将实体用于任何其他操作,您可能需要传回从合并返回的实体。

关于java - JPA 多对一关系 CascadeType 行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36757723/

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