是否可以在没有对象到对象映射的情况下强制执行外键?

时间:2010-01-21 17:20:47

标签: java hibernate foreign-keys hibernate-mapping

假设提供了以下映射:

<class name="A" table="a_table">
  <id name="id"/>
  <many-to-one name="entityB" column="fk_B" not-null="false" unique="true"/>
</class>

<class name="B" table="b_table">
  <id name="id"/>
</class>

Java类:

public class A {
   private long id;
   private B entityB;
   // getters and setters skipped
}

是否可以更改Hibernate映射,以便Hibernate在启动时仍然强制执行外键,但类A将如下所示:

public class A {
   private long id;
   private long idOfB;
   // getters and setters skipped
}

我理解,如果我将<many-to-one...转换为<property...,这将有效,但数据库不会强制使用外键。

我需要这样做,因为对象B可能(或可能不会)单独初始化,这有时会导致 调用org.hibernate.LazyInitializationException: could not initialize proxy - no Session时发生的a.getB()例外情况。我希望将它作为long idOfB并在必要时加载整个对象;这样也可以加快对象A的加载速度。

我相信我的问题与this one非常相似,但提供的解决方案(使用延迟加载)在我的情况下是不合适的,因为即使我调用a.getB().getId(),我也会{{} 1}}如果我打电话给LazyInitializationException,我就不会。

非常感谢。

4 个答案:

答案 0 :(得分:9)

如上所述

  

据我所知,如果我将&lt; many-to-one ...转换为&lt; property ...这样可行,但数据库不会强制执行外键。< / p>

所以我的建议是:同时使用

public class EntityA {

    private Integer idOfB;

    private EntityB entityB;

    // getter's and setter's

}

<class name="A" table="a_table">
    <id name="id"/>
    <property name="idOfB" column="fk_B" not-null="false" unique="true"/>
    <many-to-one name="entityB" update="false" insert="false" column="fk_B"/>
</class>

请注意,当两个属性共享同一列时,您必须在一个属性中放置有关它的设置。否则,Hibernate会抱怨一些错误。它解释了为什么我在entityB属性中定义update =“false”和insert =“false”。

的问候,

答案 1 :(得分:4)

您始终可以在hibernate hbm.xml文件中手动创建外键DDL:

<hibernate-mapping>
    ...
    <database-object>
        <create>[CREATE FK]</create>
        <drop>[DROP FK]</drop>
    </database-object> 
</hibernate-mapping>

如果需要支持不同的方言,您也可以使用此范围。

查看5.7. Auxiliary database objects

答案 2 :(得分:0)

您可以采用的另一种方法是使用B映射而不是A映射来定义FK。我已经添加了JPA代码,如果你没有使用注释,你必须将它转换为你的hibernate映射文件。

@Entity
public class B
{
    private long id;
    private List<A> aList;

    @Id
    @Column( name = "ID" )
    public long getId()
    {
        return id;
    }

    @OneToMany
    @JoinColumn( name = "B_ID" )
    public List<A> getAList()
    {
        return aList;
    }
    public void setId( long id )
    {
        this.id = id;
    }
    public void setAList( List<A> aList )
    {
        this.aList = aList;
    }        
}

A.java看起来不像这样:

@Entity
public class A
{
    private long id;
    private long idOfB;

    @Id
    @Column( name = "ID" )
    public long getId()
    {
        return id;
    }
    @Column( name = "B_ID" )
    public long getIdOfB()
    {
        return idOfB;
    }
    public void setId( long id )
    {
        this.id = id;
    }
    public void setIdOfB( long idOfB )
    {
        this.idOfB = idOfB;
    }   
}

答案 3 :(得分:0)

我建议您将对象关联到对象以充分利用Hibernate。我认为问题是你得到的例外。这是因为当您尝试获取惰性对象时,Hibernate会话已经关闭。此博客中有几个帖子显示了此问题的答案,例如:link text

如果你使用的是spring,你可以使用OpenEntityManagerInViewFilter,这样会话就会一直打开,直到视图呈现为止。