2012-10-08 28 views
1

我正在使用JPA 2與Hibernate版本。 4.1.7。最終作爲JPA實施。我也使用Spring框架v 3.1.2.RELEASE來清楚。這是我的問題。在persist()之後但在flush()之前更改JPA實體不起作用

我寫了一個方法來添加/更新我的用戶實體。

@Override 
@Transactional 
public void saveUser(UserForm userForm) { 
    User user; 

    if (userForm.getId() == null) { // new user 
     user = new User(); 
     user.setCreationDate(new Date()); 
     entityManager.persist(user); // !!! 
    } else { 
     user = entityManager.find(User.class, userForm.getId()); 
    } 

    user.setFirstName(userForm.getFirstName()); 
    user.setLastName(userForm.getLastName()); 
    user.setMiddleName(userForm.getMiddleName()); 

    user.setEmail(userForm.getEmail()); 

    user.setRole(entityManager.find(Role.class, 1));//TODO 

    user.setLogin(userForm.getLogin()); 
    user.setPassword(userForm.getPassword1()); 

    entityManager.flush(); 
} 

我正在測試用戶(userForm.getId()== null)的添加。和上面的代碼不能正常工作,給錯誤:

javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: Column 'first_name' cannot be null 
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1377) 
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1300) 
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1306) 
at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:989) 
... 

不過。如果我提出呼籲刷新之前,堅持()到最後()一切工作正常:

@Override 
@Transactional 
public void saveUser(UserForm userForm) { 
    User user; 

    if (userForm.getId() == null) { // new user 
     user = new User(); 
     user.setCreationDate(new Date()); 
    } else { 
     user = entityManager.find(User.class, userForm.getId()); 
    } 

    user.setFirstName(userForm.getFirstName()); 
    user.setLastName(userForm.getLastName()); 
    user.setMiddleName(userForm.getMiddleName()); 

    user.setEmail(userForm.getEmail()); 

    user.setRole(entityManager.find(Role.class, 1));//TODO 

    user.setLogin(userForm.getLogin()); 
    user.setPassword(userForm.getPassword1()); 

    entityManager.persist(user);// !!! 
    entityManager.flush(); 
} 

我認爲發生的事情是在第一個(問題)情況下,它試圖存儲用戶對象數據存在的時間持續調用,儘管在flush()期間執行的實際保存()(upd。錯誤,它嘗試在persist()調用時正好發出sql插入)。是什麼讓我這樣想?當我嘗試調試時,我發現它仍然嘗試在裏面插入正確的creation_date,但其他值是空值。

但是我發誓在幾年前我一直在工作的其他項目中,這工作得很好,儘管之後我使用了Oracle而不是MySQL(我不認爲這是原因),而且舊版本的框架。

這裏有什麼問題?也許有一些Hibernate的配置選項影響這個?

或者這是正確的行爲和我對JPA API的誤解?

UPD。我正在使用

@Id 
@GeneratedValue 
@Column(columnDefinition="INT") 
private int id; 

對於User entiry中的id字段。我相信這意味着生成策略= AUTO,適用於mysql auto_increment鍵。

+2

聽起來這可能是使用IDENTITY進行PK生成的問題。這是在用什麼? –

+1

我同意,如果身份證號是身份,則需要立即插入。所以如果可能的話切換到Sequence或TableGenerator。如果你不能,那麼修改過的代碼是正確的,但我會爲persist()調用添加空檢查以避免級聯檢查。 –

+0

@SteveEbersole請在我的帖子末尾查看用戶實體的id字段的更新內容。我認爲在MySQL自動的情況下意味着與IDENTITY相同? – Xonix

回答

1

您將您的用戶名設置爲空(user.setFirstName(userForm.getFirstName());),因爲userForm.getFirstName()返回null,並且您的錯誤顯示:Column 'first_name' cannot be null

您應該檢查爲什麼userForm.getFirstName()返回null或允許用戶的名字爲空,因爲您當前的實體配置不允許這樣做。

也許你可以告訴我們用戶實體?

+1

這完全是不真實的。堅持使得「持久性上下文」(又名EntityManger)意識到該實體。 flush是將內存中狀態同步到數據庫的過程。 –

+0

是的,我的不好。這在這種情況下不是問題。我刪除了錯誤的部分。 – Minutis

1

這就是正確的行爲。在第一次調用persist()時,用戶的firstName爲null。在這之後你已經設置了第一個名字,但是在刷新之前,JPA/Hibernate準備好的命令類似於:

在持久化時,用戶對象的狀態可以說,user @ version1 插入用戶值(id,creationdate,null,null ..)從用戶@ VERSION1對象

現在,一個新的用戶版本存在用戶@版本2

在沖水時,

檢查任何未決的插入/更新..把所有的對象VERSION1,這是在最後堅持的時候。

請注意,刷新可能會或可能不會在數據庫中執行物理插入操作,但會使對象處於正確狀態,這意味着非持久性更改將會丟失。

不要擔心,如果它工作正常,可能與休眠3之前,並開始不工作時,當你遷移到休眠4.我有幾個問題,其中休眠3沒有問題,但不工作在休眠4沒有額外的修復。

相關問題