簡體   English   中英

Spring數據jpa分離實體

[英]Spring data jpa detached entity

我開始使用Spring Data JPA在Spring Boot應用程序上設置用戶和角色之間的ManyToMany關系。

此關系在User類中定義如下:

@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinTable(name="user_role", joinColumns = {@JoinColumn(name="user_id")}, inverseJoinColumns = {@JoinColumn(name="role_id")})
private Set<UserRole> roles;

我用以下方法創建角色

@Transactional
private void generateSeedRoles() {
    UserRole adminRole = new UserRole(RoleEnum.ADMIN.toString());
    userRoleRepository.save(adminRole);

    UserRole userRole = new UserRole(RoleEnum.USER.toString());
    userRoleRepository.save(userRole);
}

之后為用戶分配角色失敗:

@Transactional
private void generateSeedUsers() {
    UserRole adminRole = userRoleRepository.findUserRoleByRoleName("ADMIN");

    User user = User.createUser("user1", "user1@user.com", "pass");
    user.setRoles(new HashSet<UserRole>(Arrays.asList(adminRole)));

    userRepository.save(user);
}

拋出以下異常(為便於閱讀而格式化):

org.springframework.dao.InvalidDataAccessApiUsageException: 
detached entity passed to persist: co.feeb.models.UserRole; 
nested exception is org.hibernate.PersistentObjectException: 
detached entity passed to persist: co.feeb.models.UserRole

但是,如果在創建關系之前保存用戶,則它可以正常工作:

@Transactional
private void generateSeedUsers() {
    UserRole adminRole = userRoleRepository.findUserRoleByRoleName("ADMIN");

    User user = User.createUser("user1", "user1@user.com", "pass");
    //Save user
    userRepository.save(user);

    //Build relationship and update user
    user.setRoles(new HashSet<UserRole>(Arrays.asList(adminRole)));
    userRepository.save(user);
}

必須保存/更新用戶兩次對我來說似乎有些不合理。 有沒有辦法將收到的角色分配給新用戶而不先保存用戶?

當您保存實體時,Spring會在內部檢查實體是否是新的(我忘記確切的機制),並發出持久性(如果是新的)或合並(如果存在)。

由於您已經使用Cascade.ALL定義了User與UserRole的關系,因此來自User的任何持久/合並也將級聯到UserRole。

鑒於Spring如何實現保存以及上面級聯的行為,以下是一些需要考慮的方案:

  • 如果User和UserRole都是新的 - 你在保存用戶時會得到一個持久的動作,並且一個級聯持久存在UserRole,由於UserRole是新的,因此工作正常。
  • 如果User是新的但UserRole已經存在 - 再次保存User時會得到一個持久動作,並且級聯持續存在UserRole,這會導致錯誤,因為UserRole已經存在!

如果您可以保證添加到用戶關系的任何UserRole始終存在,您只需從級聯選項中刪除Cascade.Persist即可。 否則,我相信在上述兩種情況下保存用戶時,您必須使用合並 - 通過自定義存儲庫和entityManager。

關於你使用Cascade.ALL,在這種情況下可能沒有意義,因為你有一個@ManyToMany關系,從用戶到UserRole級聯ALL可能會產生一些不良影響(例如Cascade.Remove會每次刪除UserRole用戶被刪除)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM