JPA多对一关系CascadeType行为

时间:2016-04-21 00:52:58

标签: java jpa persistence eclipselink

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

我的应用程序的逻辑:当我创建新的Loan对象并设置相应的user时,它应为唯一用户创建一个新对象或设置id的{​​{1}} 1}}进入user现有用户。

为此,我的数据库在user_idfirst_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()

1 个答案:

答案 0 :(得分:1)

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

b)如果未设置cascade.PERSIST(或cascade.ALL)并且引用用户是新用户,则会找到"找到新对象"异常。

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

请注意,使用merge与Persist的不同之处在于,传入的内容不会被上下文管理。这意味着在事务提交之后,传入的实体仍然没有设置任何主键值。如果要继续将实体用于任何其他操作,您可能希望传回从Merge返回的实体。