2009-11-09 11 views
6

Mam dwa powiązane obiekty biznesowe - A i B. powiązanie to (A-> B) wiele do jednego, z B.Id a klucz obcy w A (więc A ma A.B_id w DB).NHibernate - dostęp do identyfikatora powiązanego obiektu bez leniwego ładowania całego obiektu

Używam lazy = true i rozwiązałem większość moich problemów, jednak w A To ToString chcę wydrukować również A.B.Id, które powinienem mieć bez dalszych wycieczek do DB. ale dostęp do A.B aktywuje proxy, a ponieważ nie jest to w kontekście otwartej sesji, zgłasza wyjątek.

jednym łatwym, ale brzydkim rozwiązaniem byłoby posiadanie własności A.B_id. ale to jest część rzeczy, których staraliśmy się unikać w pierwszej kolejności. jakikolwiek "ekologiczny" sposób na zrobienie tego? :) dzięki!


AKTUALIZACJA: po prostu przeczytaj o buforowaniu i sesji. Przejdź do sesji. Prześlij. zanim będę tylko nowy, który rzuci wyjątek, jeśli obiekt nie istnieje (Session.Load), a drugi zwraca obiekt zerowy (Session.Get). po przeczytaniu o buforowaniu here, jasne jest, że Session.Load zwraca proxy do obiektu, i tylko leniwie pobiera je, gdy dostęp do właściwości innej niż ID jest dostępny, co jest bardzo podobne do tego, czego potrzebuję od skojarzeń! na razie dodałem oddzielne identyfikatory obiektów (dodano B_Id do A, więc mogę uzyskać do nich dostęp jako A.B_Id zamiast ABId)

+0

Dlaczego chcesz to zrobić? – Paco

+0

jak już wspomniałem, tylko dla drukowania dziennika itp., W A To ToString(). Nie potrzebuję innych pól z B. tylko identyfikator. –

Odpowiedz

3

Z tego samego powodu użyłem jawnych właściwości AB-ID dla wszystkich moich wielu do jednego związku. Nie uważam tego za szybkie i brudne rozwiązanie, ponieważ zapewnia rozwiązanie tego problemu, a także duża elastyczność to obszar oszczędzania i aktualizacji, tj. Nie muszę pobierać z bazy danych obiektu B tylko po to, aby przypisać go do A w aby utworzyć powiązanie, gdy mam B_ID w ciągu zapytania lub gdzieś indziej.

Moje pliki mapowania useually wyglądać następująco:

<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" /> 

Jak widać jedną z 2 mieszkań ma być tylko do odczytu, aby uniknąć konieczności NHibernate wysyłania 2 razy tej kolumny w bazie danych, gdy wkładki lub updatas są wydarzenie. Powyższe sprawia, że ​​są one tylko do odczytu (przy użyciu atrybutów insert = "false" update = "false"), ale możesz zamiast tego mieć właściwość CreatorID tylko do odczytu, jeśli chcesz.

Mając tylko wiele do jednego, nie masz własności w swojej klasie A, aby utrzymać wartość B.ID. Jedynym sposobem na uzyskanie go jest uzyskanie dostępu do obiektu B, który uruchomi proxy, i odpali zapytanie do bazy danych (jeśli nie jest już załadowana do sesji).

Z przyjemnością wysłucham każdej innej opcji, która zapewnia rozwiązanie i oferuje ten sam rodzaj elastyczności.

+0

Nadal chciałbym, żeby to można było zrobić za pomocą właśnie ABId - nie podoba mi się duplikat danych - miałem te właściwości i * usunięto * je ... Zbadam sprawę dalej, ale na razie to właśnie zrobię . dzięki! –

+0

@YonatanKarni W pełni się zgadzam. Istnieje również poważny problem z wydajnością. Dodaj dużą liczbę, n, elementów 'proxy' do kolekcji encji (z ustawionym typem podkładu) i zabija wydajność, ponieważ n selects, jeden na proxy, są wykonywane sekwencyjnie, jak robi to 'set.Add' rzecz. – jasper

5

Jeśli używasz NHibernate 3.2 lub nowszej, można użyć następującego kodu, aby uzyskać identyfikator powiązanego obiektu bez innej obie strony do bazy danych, aby załadować cały obiekt:

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; 
    } 
} 
1

Można użyć metody GetIdentifier z Sesja Nhibernate:

session.GetIdentifier(obj);