2010-01-21 1 views
4

Предполагая, что предусмотрены следующие отображения:Можно ли использовать внешний ключ без привязки объекта к объекту?

<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 при запуске, но класс 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(), я бы получить LazyInitializationException тогда, если я называю a.getIdOfB() я Wouldn» т.

Большое спасибо за внимание.

+0

Настоятельно рекомендую использовать LazyLoading, а не изобретать колесо. Вы получили бы типы безопасных классов объектов, точно такую ​​же производительность и могли бы покончить с пользовательским кодом перезагрузки. Обратите внимание, что LazyLoading приводит к тому, что LazyLoadingException используется неправильно, то есть если запрошенная ленивая загрузка запрашивается после закрытия сеанса. Также обратите внимание, что запрос идентификатора объекта не приводит к загрузке объекта. Я рекомендую вам задать вопрос с конкретными проблемами, которые возникают с LazyLoading. – meriton

+0

Поверьте, я использую LazyLoading. Это всего лишь один случай из сотен, где я не могу. В противном случае я не стал бы спрашивать. – mindas

+0

Связанный вопрос: [java - Hibernate - внешние ключи вместо сущностей] (http://stackoverflow.com/questions/6311776/hibernate-foreign-keys-instead-ofentities). –

ответ

7

Как сказал

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

Так что мой совет: использовать как

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" и insert = "false" в свойстве entityB.

приветствует,

+0

Хороший и гладкий! И это работает ... – mindas

+0

Как бы я разместил это с помощью jackson – gabber12

4

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

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

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

Заканчивать 5.7. Auxiliary database objects

0

Другой подход можно принять, чтобы определить FK с отображением B, а не отображение. Я добавил код 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; 
    } 
} 
0

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

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

+0

Спасибо за ваш ответ, но я полностью осознаю, почему бросаются ленивые ошибки загрузки и как с ними бороться. Однако это особый случай, когда я хотел бы, чтобы структура была более гибкой и выполняла мою работу. Потому что именно поэтому они написаны, верно? Наконец, я не думаю, что то, что я прошу, слишком много для структуры отображения O-R, не так ли? – mindas