2016-04-21 110 views
0

我有2個表格:UserLoan。用戶有3個字段:id(PK),first_namelast_nameLoan表有場user_id是外鍵User表: enter image description hereJPA多對一關係CascadeType行爲

我的應用程序的邏輯:當我創造新的Loan對象,並設置有相應的user應建立新的獨特的用戶一個新的或設置iduser納入現有用戶的user_id

爲此,我的數據庫在first_name,last_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爲DB。但是,當我嘗試添加一個現有的我和異常:

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)我只能夠進入現有的用戶,因爲只有我通過未在DB我堅持一個新的得到一個例外:

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)沒有工作。

UPDATE

插入代碼的新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); 
      } 
     } 
+1

向我們顯示您的代碼插入。 –

+0

請張貼用戶類的代碼。 – LearningPhase

+0

我更新了問題,謝謝 – DimaSan

回答

1

如果調用級聯的貸款 一)堅持。用戶關係和參考我們如果用戶實例沒有從同一個EntityManager實例/上下文中讀入,你會得到一個異常 - 你正在通過userService讀取它,然後將貸款保存在loanService中,所以上下文必須被容器管理並在相同的交易中工作。 b)如果未設置cascade.PERSIST(或cascade.ALL),並且引用用戶是新的,則會出現「找到新對象」異常。

如果您不能在同一個EntityManager中執行用戶讀取操作,那麼您將要保存貸款,切換到使用合併可能會有所幫助,因爲JPA應該隨後檢查所引用的實體並進行合適的合併。然後,您需要在合併的關係上設置cascade.MERGE選項,以將其應用於用戶實例。

請注意,使用合併不同於Persist,因爲您傳遞的內容不受上下文管理。這意味着在事務提交之後,傳入的實體仍然沒有設置任何主鍵值。如果您要繼續將實體用於任何其他操作,您可能想要傳回從合併中返回的實體。

+0

謝謝克里斯的詳細解答。我認爲你是對的 - 問題是使用了2個不同的EntityManager實例。我會嘗試在同一個實例中執行操作。 – DimaSan