簡體   English   中英

休眠彈簧:@ManyToMany DataIntegrityViolationException ConstraintViolationException

[英]Hibernate Spring: @ManyToMany DataIntegrityViolationException ConstraintViolationException

我正在為ManyToMany之間的關系構建示例:User(1)-( )AccessLevel( )-(1)Role

我用休眠實現在Java中實現了3個類,如下所示:

班級用戶

@Entity
@Table(name="user")
public class User {
    @Id
    @GeneratedValue
    @Column(name="USER_ID")

    @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinTable(name = "access_level", joinColumns = { 
            @JoinColumn(name = "user_id", nullable = false, updatable = false) }, 
            inverseJoinColumns = { @JoinColumn(name = "role_id", nullable = false, updatable = false) })
    private Set<Role> roles = new HashSet<Role>(0);

類角色

@Entity
@Table(name="role")
public class Role {

    @Id
    @GeneratedValue
    @Column(name="role_id")
    private Integer id;

    @Column(name="role_name")
    private String roleName;

類訪問級別

@Entity
@Table(name="access_level")
public class AccessLevel {

    @Id
    @GeneratedValue
    private Integer id;
    @Column(name="role_id")
    private Integer  roleId;
    @Column(name="user_id")
    private Integer  userId;

問題:

當我使用merge方法持久化User Bean時,會出現異常:

@Service
public class UserServiceImpl implements UserService {

    @PersistenceContext
    private EntityManager em;

    @Override
    @Transactional
    public void save(User user) {
        em.merge(user);
    }

例外

org.springframework.web.util.NestedServletException:請求過程

ing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: Could not execute JDBC batch update; SQL [insert into access_level (user_id, role_id) values (?, ?)]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
    org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:894)
    org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:722)

如您所見,hibernate正在嘗試運行此查詢:

insert into access_level (user_id, role_id) values (?, ?)

從我的角度來看,即使我已將@GeneratedValue添加到id屬性,似乎休眠狀態也沒有為AccessLevel生成主鍵。

注意:我正在使用Postgresql的生產環境和使用HSQL數據庫的開發環境,該環境根據實體描述從一開始就創建所有架構。 兩種環境都會產生相同的問題。

問候,克里斯蒂安科羅拉多

原因:

似乎對於ManyToMany關系,您不需要為“聯接表”定義一個類。 因此,如果我取消AccessLevel實體,則邏輯將工作正常。 我進一步解釋:

說明:

在定義User類時,我還描述了與Role的關系:

@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinTable(name = "access_level", joinColumns = { 
            @JoinColumn(name = "user_id", nullable = false, updatable = false) }, 
            inverseJoinColumns = { @JoinColumn(name = "role_id", nullable = false, updatable = false) })
    private Set<Role> roles = new HashSet<Role>(0);

重要的是,我已經告訴休眠狀態,用戶實體將通過稱為“ access_level”的表與角色實體相關,並且該表將具有user_id和role_id列,以便加入先前的實體。

到目前為止,所有這些都是休眠的,以便處理多對多關系,因此在合並時,它將使用該信息來創建和調整此腳本:

insert into access_level (user_id, role_id) values (?, ?)

現在,當我為AccessLevel定義一個新實體時出現了問題:

@Entity
    @Table(name="access_level")
    public class AccessLevel {

        @Id
        @GeneratedValue
        private Integer id;
        @Column(name="role_id")
        private Integer  roleId;
        @Column(name="user_id")
        private Integer  userId;

現在,我告訴休眠狀態,有一個與AccessLevel實體相關的表“ access_level”,它具有3列,最重要的是Id,它是主鍵。

所以我兩次定義了“ access_level”!

解:

  • 我刪除了用於access_level表的實體。
  • 我重新編寫了生產腳本,以便僅具有user_id / role_id列的“ access_level”。

注意:最好知道如何在聯接表中添加主鍵而不產生問題。 另一種選擇是在數據庫中添加一個組合的主鍵(user_id / role_id),該主鍵與休眠無關。

為什么在聯接表中需要PK列? 將有一個由user_id和role_id組成的復合PK。 現在,您已經發現@ManyToMany的JoinTable只會有兩列,有時您可能需要有關此關系的其他數據。

例如

user_id role_id date_granted

然后,您可能要使用AccessLevel實體,但是您可以將@ManyToMany替換為@OneToMany,從用戶到AccessLevel,也可以選擇從角色> AccessLevel。

Hibernate文檔本身建議不要使用@ManyToMany:

不要使用外來關聯映射:

真正的多對多關聯的實際測試案例很少見。 大多數時候,您需要存儲在“鏈接表”中的其他信息。 在這種情況下,最好將兩個一對多關聯用於中間鏈接類。 實際上,大多數關聯是一對多和多對一的。 因此,在使用任何其他關聯樣式時,您應謹慎進行。

暫無
暫無

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

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