在映射同一实体两次时,Hibernate中的双外键

时间:2014-10-09 15:11:41

标签: java hibernate

通常的做法是将相同的实体映射两次甚至三次,每次都需要处理所需的列子集。我发现使用Hibernate 3.5.1,每次映射同一个表的两个实体中存在@ManyToOne@OneToMany时,外键会被创建两次。这对MySQL和SQL Server没有影响,但Oracle拒绝第二个创建语句。

以下是一个例子:

@Entity
@javax.persistence.SequenceGenerator(name = "SEQ_STORE", sequenceName = "SEQ_ENTITY")
@Table(name = "ENTITIES")
class Entity {

    //All columns


    //And then.....
    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "BRIDGE_TABLE", joinColumns = { @JoinColumn(name = "ENTITY_ID") }, inverseJoinColumns = { @JoinColumn(name = "ROLE_ID") })
    @OrderBy("id DESC")
    private Set<Role> roles = new HashSet<Roles>();
}

@Entity
@javax.persistence.SequenceGenerator(name = "SEQ_STORE", sequenceName = "SEQ_ENTITY")
@Table(name = "ENTITIES")
class EntityListItem {

    //Only a subset of the previous columns


    //And then.....
    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "BRIDGE_TABLE", joinColumns = { @JoinColumn(name = "ENTITY_ID") }, inverseJoinColumns = { @JoinColumn(name = "ROLE_ID") })
    @OrderBy("id DESC")
    private Set<Role> roles = new HashSet<Roles>();
}

目前,Role的设计不能导航到Entity(否则我猜会有4个外键)。

以下是Hibernate发布的声明:

create table BRIDGE_TABLE (ENTITY_ID number(19,0) not null, ROLE_ID varchar2(60 char) not null, primary key (ENTITY_ID, ROLE_ID)); //Creates the table
alter table BRIDGE_TABLE add constraint FK47CFB9F0B068EF3F foreign key (ENTITY_ID) references ENTITIES;
alter table BRIDGE_TABLE add constraint FK47CFB9F0B068EF3F foreign key (ENTITY_ID) references ENTITIES;

我不确定这是否是一个Hibernate错误。我们目前无法迁移到Hibernate 4.可以通过代码修复它还是需要一个新的Hibernate版本?

1 个答案:

答案 0 :(得分:0)

我做了一个解决方法:

  1. 向两个实体添加具有相同FK名称的@ForeignKey注释(例如@ForeignKey(name = "FK_TO_ENTITY", inverseName = "FK_TO_ROLE")
  2. 如下所示扩展LocalSessionFactoryBean

  3. @override
    public void createDatabaseSchema() throws DataAccessException
    {
        logger.info("Creating database schema for Hibernate SessionFactory");
    
        SessionFactory sessionFactory = getSessionFactory();
        final Dialect dialect = ((SessionFactoryImplementor) sessionFactory).getDialect();
    
        final LinkedHashSet<String> sql = new LinkedHashSet<String>();
        for (String query : getConfiguration().generateSchemaCreationScript(dialect))
            sql.add(query);
    
        HibernateTemplate hibernateTemplate = new HibernateTemplate(sessionFactory);
        hibernateTemplate.execute(new HibernateCallback<Void>()
        {
            @Override
            public Void doInHibernate(Session session) throws SQLException
            {
                session.doWork(new Work()
                {
                    @Override
                    public void execute(Connection conn) throws SQLException
                    {
                        PhoenixAnnotationSessionFactoryBean.this.executeSchemaScript(conn, sql.toArray(new String[0]));
                    }
                });
    
                return null;
            }
        });
    
    }
    

    原因:@ForeignKey注释确保FK具有相同的名称,因此SQL语句将彼此相等。覆盖LSFB将存储在Set中创建模式所需的SQL查询,以便不允许重复。