Возможно ли применять внешний ключ без сопоставления объекта с объектом? - PullRequest
6 голосов
/ 21 января 2010

При условии предоставления следующих сопоставлений:

<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.

Я полагаю, что мой вопрос очень похож на на этот , однако предлагаемое решение (для использования отложенной загрузки) не подходит в моем случае, так как даже если я позвоню a.getB().getId(), я получу LazyInitializationException тогда как если бы я позвонил a.getIdOfB(), я бы не стал.

Заранее большое спасибо.

Ответы [ 4 ]

10 голосов
/ 26 января 2010

Как сказал

Я понимаю, что если я преобразую <много-к-одному ... в <свойство ... это сработает, <strong>, но внешний ключ не будет принудительно применяться в базе данных.

Итак, мой совет: используйте оба

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 будет жаловаться на некоторые ошибки. Это объясняет, почему я определяю update = "false" и вставляем = "false" в свойстве entityB.

С уважением,

4 голосов
/ 25 января 2010

Вы всегда можете создать DDL внешнего ключа вручную в файле hibernate hbm.xml:

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

Вы также можете указать это, если необходимо поддерживать разные диалекты.

Выезд 5.7. Вспомогательные объекты базы данных

0 голосов
/ 25 января 2010

Я рекомендую вам связывать объекты с объектами, чтобы получить все преимущества Hibernate. Я думаю, что проблема - исключение, которое вы получаете. Это потому, что сеанс Hibernate уже закрыт, когда вы пытаетесь получить ленивый объект. В этом блоге есть несколько сообщений, в которых показаны ответы на эту проблему, например: текст ссылки .

Если вы используете spring, вы можете использовать OpenEntityManagerInViewFilter, чтобы сессия оставалась открытой до тех пор, пока представление не будет отображено.

0 голосов
/ 25 января 2010

Другой подход, который вы могли бы использовать, - это определить FK с вашим B-отображением, а не с A-отображением. Я добавил код JPA, вам нужно будет перевести его в файл отображения спящего режима, если вы не используете аннотации.

@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;
    }   
}
...