Hibernate Annotation - 如何连接三个具有多对多关系的表

Posted

技术标签:

【中文标题】Hibernate Annotation - 如何连接三个具有多对多关系的表【英文标题】:Hibernate Annotatoin - How to Join Three Tables with many to many relationship 【发布时间】:2014-01-22 00:00:24 【问题描述】:

    我有 3 个实体 USER、APPLICATION 和 ROLE。

      我希望将 ID 连接到名为 USER_APP_ROLE(user_ID, application_ID, role_ID) 的表中,它们之间存在多对多关系。 我想要这种结构的原因是 - 我需要允许用户处理具有多个角色的多个应用程序。 我做了以下代码:

    用户.java @ManyToMany (targetEntity=Role.class) @JoinTable(name="USER_APPLICATION_ROLE", joinColumns=@JoinColumn(name="USER_ID"), inverseJoinColumns=@JoinColumn(name="ROLE_ID")) 私人收藏角色;

      @ManyToMany (targetEntity=Application.class)
      @JoinTable(name="USER_APPLICATION_ROLE",
      joinColumns=@JoinColumn(name="USER_ID"),
      inverseJoinColumns=@JoinColumn(name="APPLICATION_ID"))
      private Collection<Application> applications;
    
      Role.java
      @ManyToMany(mappedBy="roles", targetEntity=User.class)
      private Collection<User> users = new ArrayList<User>();
    
      Application.java
      @ManyToMany(mappedBy="applications", targetEntity=User.class)
      private Collection<User> users = new ArrayList<User>();
    
      当我尝试运行以下测试时:

    user.getRoles().add(role1); user.getRoles().add(role2);

    role1.getUsers().add(user); role1.getUsers().add(user);

    role2.getUsers().add(user); role2.getUsers().add(user);

    user.getApplications().add(app1); user.getApplications().add(app2);

    app1.getUsers().add(user); app2.getUsers().add(user);

    ......

    session.beginTransaction(); 会话.保存(用户); session.save(role1); session.save(role2); session.save(app1); session.save(app2);

    I get the following error:
    
    
    
          Hibernate: select seq_cm_user.nextval from dual
           Hibernate: select seq_role.nextval from dual
    Hibernate: select seq_role.nextval from dual
    Hibernate: select seq_application.nextval from dual
    Hibernate: select seq_application.nextval from dual
    Hibernate: insert into CM_USER (EMAIL, FIRST_NAME, LAST_NAME, MIDDLE_NAME, USERNAME, ID) values (?, ?, ?, ?, ?, ?)
    Hibernate: insert into CM_ROLE (DESCRIPTION, ID) values (?, ?)
    Hibernate: insert into CM_ROLE (DESCRIPTION, ID) values (?, ?)
    Hibernate: insert into CM_APPLICATION (CODE, DESCRIPTION, ID) values (?, ?, ?)
    Hibernate: insert into CM_APPLICATION (CODE, DESCRIPTION, ID) values (?, ?, ?)
    Hibernate: insert into USER_APPLICATION_ROLE (USER_ID, APPLICATION_ID) values (?, ?)
    Hibernate: insert into USER_APPLICATION_ROLE (USER_ID, APPLICATION_ID) values (?, ?)
    Exception in thread "main" org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
        at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
        at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
        at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
        at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:114)
        at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:109)
        at org.hibernate.jdbc.AbstractBatcher.prepareBatchStatement(AbstractBatcher.java:244)
        at org.hibernate.persister.collection.AbstractCollectionPersister.recreate(AbstractCollectionPersister.java:1179)
        at org.hibernate.action.CollectionRecreateAction.execute(CollectionRecreateAction.java:58)
        at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:265)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:188)
        at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
        at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
        at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
        at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)
        at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
        at com.hp.gdas.capman.HibernateTest.main(HibernateTest.java:73)
    Caused by: java.sql.BatchUpdateException: ORA-01400: cannot insert NULL into ("SYSTEM"."USER_APPLICATION_ROLE"."ROLE_ID")
    
        at oracle.jdbc.driver.DatabaseError.throwBatchUpdateException(DatabaseError.java:343)
        at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:10657)
        at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
        at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
        ... 14 more
    

    6.我可能做错了方向。如果我完全做错了,请帮助并建议我任何替代方法。感谢任何帮助。

谢谢。

【问题讨论】:

这根本与您的 ORM 结构无关;您将null 插入到不允许该列为null 的表中。我们对您的 DDL 了解不足,无法告诉您它发生在哪里;您应该弄清楚哪些列是明确的NOT NULL,并确保您设置的数据尊重这一点。 @Makoto :我不太关心错误。我关心如何在 Hibernate 中实现此要求(即 User-App-Role 映射)。我只是根据我的知识创建,所以我得到了错误。由于我是 Hibernate 的新手,你能举个例子来满足这个映射吗? 【参考方案1】:

您似乎希望 USER_APPLICATION_ROLE 表包含为应用程序中的用户分配的角色。但这不是您的映射所做的。它的作用是使用此表来包含用户的角色(忽略应用程序),以及用户的应用程序(忽略角色)。

因此,您的映射是错误的。您需要将 USER_APPLICATION_ROLE 表映射为一个实体,因为它不是两个实体之间的纯连接表。例如,您可以将其命名为 UserApplicationRole。用户将具有与 UserApplicationRole 的 OneToMany 关联。 UserApplicationRole 将与 User 以及 Role 和 Application 具有 ManyToOne 关联。我强烈建议您在此表中添加一个自动生成的 ID 列,就像为您的所有实体一样。

【讨论】:

,我是hibernate的新手。所以如果可能的话,你能不能创建一个简单的例子来说明你的评论。如果我想知道“用户(例如Hemant)在哪个应用程序上工作,还可以使用hibernate查询以及他在每个应用程序上的角色。以下是我的示例表结构表数据用户1.Hemant 2.Andrew 3.Clerk`Application 1.App1 2.App2`Role 1.Read 2.Write 3.Delete 这很好,感谢您的启发性回答。

以上是关于Hibernate Annotation - 如何连接三个具有多对多关系的表的主要内容,如果未能解决你的问题,请参考以下文章

Spring的annotation用在set方法上 hibernate的annotation用get方法上

hibernate annotation注解方式来处理映射关系

hibernate annotation注解方式来处理映射关系

Hibernate一对一外键双向关联(Annotation配置)

Annotation版本的HelloWorld

Hibernate4集成 Annotation使用教程