NHibernate - доступ к идентификатору связанного объекта без ленивой загрузки всего объекта - PullRequest
7 голосов
/ 09 ноября 2009

У меня есть два связанных бизнес-объекта - A и B. ассоциация (A-> B) много-к-одному, с B.Id - внешний ключ в A (поэтому A имеет A.B_id в БД).

Я использую lazy = true и решил большинство моих проблем, однако в ToString я хочу напечатать также A.B.Id, который я должен иметь без дальнейших поездок в БД. но доступ к A.B активирует прокси-сервер, и, поскольку это не происходит в контексте открытого сеанса, выдает исключение.

Одним простым, но уродливым решением было бы иметь свойство A.B_id. но это часть того, чего мы пытались избежать в первую очередь. какой-нибудь "органический" способ сделать это? :) спасибо!


ОБНОВЛЕНИЕ: просто прочитайте о кешировании и Session.Get vs. Session.Load. до того, как я только что сообщу, одно создает исключение, если объект не существует (Session.Load), а другой возвращает нулевой объект (Session.Get). после прочтения о кэшировании здесь становится ясно, что Session.Load возвращает прокси-объект для объекта и только лениво извлекает его при обращении к свойству, отличному от идентификатора, что очень похоже на то, что мне нужно от ассоциаций ! на данный момент я добавил отдельные идентификаторы объекта (добавил B_Id к A, чтобы я мог получить к нему доступ как A.B_Id вместо использования A.B.Id)

Ответы [ 3 ]

6 голосов
/ 26 апреля 2012

Если вы используете NHibernate 3.2 или более позднюю версию, вы можете использовать следующий код для получения идентификатора связанного объекта без повторного обращения к базе данных для загрузки всего объекта:

using NHibernate.Proxy;
...
object id = null;
if (obj.IsProxy()) // obj is the object you want to get its identifier.
{
    var proxy = obj as INHibernateProxy;
    if (proxy != null)
    {
        var li = proxy.HibernateLazyInitializer;
        if (li != null) 
            id = li.Identifier;
    }
}
4 голосов
/ 09 ноября 2009

По той же самой причине я использовал явные свойства A.B-ID для всех моих отношений многие-к-одному. Я не рассматриваю это как быстрое и грязное решение, так как оно обеспечивает решение этой проблемы, а также большую гибкость в области сохранения и обновления, т.е. мне не нужно извлекать из базы данных объект B, просто чтобы назначить его A в Чтобы создать ассоциацию, когда у меня есть B_ID в строке запроса или где-то еще.

Мои файлы сопоставления обычно выглядят так:

<property name="CreatorID" column="CreatorID" type="Int32" not-null="true" />
<many-to-one name="Creator" column="CreatorID" class="SystemUser" insert="false" update="false" cascade="none" />

Как вы можете видеть, одно из двух свойств должно быть прочитано только для того, чтобы NHibernate 2 раза не отправлял этот столбец в базу данных, когда происходит вставка или обновление. Вышеприведенное делает только для чтения (используя атрибуты insert = "false" update = "false") много-к-одному, но вместо этого вы можете иметь свойство CreatorID только для чтения, если хотите.

Имея только много-к-одному, у вас нет свойства в вашем классе сущности A для хранения значения B.ID. Единственный способ получить это - получить доступ к объекту B, который запустит прокси-сервер и отправит запрос к базе данных (если он еще не загружен в сеансе).

Я буду рад услышать любую другую опцию, которая предлагает решение и предлагает такую ​​же гибкость.

1 голос
/ 02 сентября 2016

Вы можете использовать метод GetIdentifier сеанса Nhibernate:

session.GetIdentifier(obj);
...