我有2个表:User
和Loan
。用户有3个字段:id
(PK),first_name
和last_name
。 Loan
表的字段user_id
是User
表的外键:
我的应用程序的逻辑:当我创建新的Loan
对象并设置相应的user
时,它应为唯一用户创建一个新对象或设置id
的{{1}} 1}}进入user
现有用户。
为此,我的数据库在user_id
,first_name
上有唯一索引。
last_name
课程使用Loan
User
关系:
@ManyToOne
当我添加新用户时,一切都很好,它会持续到新PK的db。但当我尝试添加一个现有的,我得到和例外:
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 ...
当我放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
时,我只能输入现有用户,因为只有我传递了一个未在DB中保留的新用户,我才得到例外:
@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()
答案 0 :(得分:1)
如果你打电话坚持贷款 a)使用cascade.Persist设置用户关系并且引用的用户存在,设置如果没有从同一个EntityManager实例/上下文中读入用户实例,您将获得异常 - 您正在通过userService读取它,然后保存贷款在loanService中,因此上下文必须是容器管理的并且在同一个事务中才能工作。
b)如果未设置cascade.PERSIST(或cascade.ALL)并且引用用户是新用户,则会找到"找到新对象"异常。
如果您无法在同一个EntityManager中执行用户读取,您将保存贷款,切换到使用合并可能会有所帮助,因为JPA应检查引用的实体并合适地合并。然后,您需要在合并关系上设置cascade.MERGE选项,以将其应用于User实例。
请注意,使用merge与Persist的不同之处在于,传入的内容不会被上下文管理。这意味着在事务提交之后,传入的实体仍然没有设置任何主键值。如果要继续将实体用于任何其他操作,您可能希望传回从Merge返回的实体。