2014-04-16 31 views
1

我正在將我的應用程序從基於xml的映射遷移到基於JPA註解的映射。但是這隻會在一個簡單的情況下失敗。例如,我有以下3個實體:@OneToMany JPA註釋導致不必要的sql更新,不會級聯

@Entitiy 
public class UserAccount { 

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) 
    @JoinColumn(name = "user_account_id", nullable = false, 
       insertable = true, updatable = false) 
    @NotNull 
    private Set<Authority> authorities; 

    @OneToOne(cascade = CascadeType.ALL) 
    @JoinColumn(name="USER_ID", nullable = false) 

    ... get and setter 
} 

@Entity 
public class Authority { 

    @Column 
    private String authority; 

    ... get and setter 
} 

@Entity 
public class User { 
    ... some properties 
} 

如果我創建一個新的UserAccount實例,並試圖挽救它,我得到了一個例外,因爲管理局實例未保存,這意味着,它不像它應該做的那樣級聯。

org.springframework.dao.InvalidDataAccessApiUsageException: 
org.hibernate.TransientObjectException: object references an unsaved transient 
instance - save the transient instance before flushing: Authority ... 

出現這種情況,因爲Hibernate試圖更新權威行(這是以前沒有插入):我用下面的服務,以節省UserAccount實例

Hibernate: 
    insert into users ... 

Hibernate: 
    insert into user_accounts ... 

Hibernate: 
    update authorities set user_account_id=? where id=? 

@Service 
public class UserAccountService { 

    @Resource 
    private UserAccountRepository userAccountRepository; 

    @Transactional(propagation = Propagation.REQUIRED, readOnly = false) 
    public void save(UserAccount userAccount) { 

     userAccountRepository.save(userAccount); 
    } 

} 

奇怪的是,該用戶實例將被保存,所以OneToOne映射級聯(如果刪除UserAccount.authorities屬性)。但是,這與基於xml的映射(並且沒有JPA)一起工作。我最終調用了一個單獨的方法來存儲Authoriy實例。

@Service 
public class UserAccountService { 

    @Resource 
    private UserAccountRepository userAccountRepository; 
    @Resource 
    private AuthorityRepository authorityRepository; 

    @Transactional(propagation = Propagation.REQUIRED, readOnly = false) 
    public void save(UserAccount userAccount) { 

     userAccountRepository.save(userAccount); 
     authorityRepository.save(userAccount.getAuthoritiesSet()); 
    } 

} 

這意味着,我手動級聯......然而,尋找到了執行的SQL語句,我可以看到,休眠插入權威實例,並在此之後,它會更新該行設置UserAccount參考:

Hibernate: 
    insert into users ... 

Hibernate: 
    insert into user_accounts ... 

Hibernate: 
    insert into authorities (authority) values (?) 

Hibernate: 
    update authorities set user_account_id=? where id=? 

對我來說這是一個性能問題,因爲有很多權威機構,我不想有20個插入,之後20個更新。但我無法「刪除」更新,並告訴hibernate將user_account_id與權限一起設置。

因爲我有許多其他對象OneToMany關係,我非常感興趣的是解決這個問題,並感謝您的幫助和想法。

休眠:4.3.4.Final, 彈簧數據的JPA:1.5.1.RELEASE

最好的問候, 丹尼爾

回答

0

...對象引用一個未保存的瞬間...」意味着您已經將子對象與父對象進行了映射,並且在保存父對象之前尚未保存該對象。

在你的情況要保存當局之前子實體當局沿節約父UserAccount

您可以使用適當的Cascade爲權限創建OneToMany關係。

@OneToMany(cascade = CascadeType.ALL) 
private Set<Authority> authorities; 

如果你有適當的級聯,你不需要像下面的行一樣分別保存權限。你可以刪除它。

authorityRepository.save(userAccount.getAuthoritiesSet()); 
+0

嗨周杰倫,但這正是我已經完成(看看我的UserAccount對象)。這真的很奇怪。 – Phillip

+0

確定嘗試刪除所有父/子映射並逐個添加並檢查問題的起始位置。 – Jay

0

我通過將hibernate版本降級到4.2.11.Final來解決了這兩個問題。我不知道,爲什麼這些問題出現在4.3.4.Final中。也許這是所有4.3.x版本的問題!

+0

這仍然是解決問題的方法嗎?我目前面臨類似的問題。 – EasterBunnyBugSmasher

+0

是的。我沒有嘗試升級到4.3.5.Final。 – Phillip

0

我與ManyToOne映射有非常類似的問題。 通過向版本字段添加默認值解決了問題。

@Version 
@Column(name = "VERSION") 
private Integer version = 1;