2010-12-16 17 views
18

Próbuję ustawić związek w następujący sposób. Każdy Mistrz pozycja ma jeden lub więcej detal elementy:Konfiguracja NHibernate dla jednokierunkowej relacji jeden-do-wielu

public class Detail { 
    public virtual Guid DetailId { get; set; } 
    public virtual string Name { get; set; } 
} 
public class Master { 
    public virtual Guid MasterId { get; set; } 
    public virtual string Name { get; set; } 
    public virtual IList<Detail> Details { get; set; } 
} 

i mapowania:

public class MasterMap : ClassMap<Master> 
{ 
    public MasterMap() 
    { 
     Id(x => x.MasterId); 
     Map(x => x.Name); 
     HasMany(x => x.Details).Not.KeyNullable.Cascade.All(); 
    } 
} 
public class DetailMap : ClassMap<Detail> 
{ 
    public DetailMap() 
    { 
     Id(x => x.Id); 
     Map(x => x.Name); 
    } 
} 

tabela bazie Master to:

masterId uniqueidentifier NOT NULL 
name  nvarchar(max) NULL 

i Szczegóły jest:

DetailId uniqueidentifier NOT NULL 
name  nvarchar(max) NULL 
MasterId uniqueidentifier NULL 
foreign key (masterId) references [Master] 

Nie bardzo zależy mi na łączu z Szczegóły z powrotem do Mistrza - w innych słowach, Obiekty szczegółowe same w sobie nie są interesujące dla mojej warstwy domeny. Będą one zawsze dostępne za pośrednictwem ich obiektu głównego.

Korzystanie kod tak:

Master mast = new Master 
{ 
    MasterId = new Guid(), 
    Name = "test", 
    Details = new List<Detail> 
    { 
     new Detail { .DetailId = new Guid(), .Name = "Test1" }, 
     new Detail { .DetailId = new Guid(), .Name = "Test1" } 
    } 
}; 

using (transaction == Session.BeginTransaction) 
{ 
    Session.Save(mast); 
    transaction.Commit(); 
} 

Działa to doskonale, z wyjątkiem szalony ograniczenia przedstawionej w this post: NHibernate robi INSERT i stawia Detail.MasterId jako NULL, potem robi aktualizację ustawić go prawdziwy MasterId.

Naprawdę, nie chcę szczegółowych wpisów z NULL MasterIds, więc jeśli ustawię pole MasterId na NOT NULL, INSERT to Detail nie powiedzie się, ponieważ jak powiedziałem NHibernate próbuje umieścić w MasterId = NULL.

Chyba moje pytanie sprowadza się do tego:

Jak mogę uzyskać powyższy przykładowy kod do pracy z moim istniejącego modelu domeny (na przykład bez dodawania właściwość Detail.Master), a pole Detail.MasterId w bazie danych ustawionej na NOT NULL?

Czy istnieje sposób, aby Nhibernate po prostu wstawił prawidłowy identyfikator MasterId w początkowym INSERT, zamiast uruchamiać później AKTUALIZACJĘ? Czy istnieje uzasadnienie dla tej decyzji projektowej? - Walczę, aby zobaczyć, dlaczego tak się stanie.

Odpowiedz

14

Nie możesz. Zacytować link z my answer na drugim pytaniu ty związane z:

Bardzo Ważna uwaga: Jeśli kolumna stowarzyszenia <one-to-many><key> NIE jest nieważna, NHibernate może powodować naruszenie więzów, gdy tworzy lub aktualizuje stowarzyszenie. Aby temu zapobiec, musisz użyć dwukierunkowego powiązania z wieloma cenionymi końcami (zestawem lub torbą) oznaczonymi jako inverse="true". Zobacz omówienie powiązań dwukierunkowych w dalszej części tego rozdziału.

Edit: jak Hazzik słusznie zauważył, to się zmieniło w NHibernate 3 i powyżej.Docs niestety nie zostały zaktualizowane, tak oto Hazzik:

[Jeśli] ustawić inverse="false" i not-null na <key>, NH3 i powyżej będzie wykonać tylko dwie wkładki INSEAD z wkładką-insert-update.

+0

czytałem, ale to naprawdę nie ma niczego wyjaśniać (nie ma dyskusji stowarzyszeń dwukierunkowych odwołanie). Czy istnieje uzasadnienie dla tej decyzji? Czy jest to ograniczenie projektu nhibernate? Czy to błąd? Jako stosunkowo początkujący użytkownik nhibernate, a nie znając w ogóle elementów wewnętrznych, wydaje się, że to powinno być możliwe. – gregmac

+0

Szczerze mówiąc, nie wiem. Nie jest klasyfikowany jako błąd przez zespół NHibernate, to tylko efekt uboczny tego, jak NHibernate utrzymuje istoty. Nie będę udawał, że znam przyczyny, ale wyobrażam sobie, że ma to coś wspólnego z agnostyką bazy danych i tożsamości. –

+4

Faktycznie, jeśli ustawiono inverse = "false" i not-null na kluczu NH3 i wyższym, wykonamy tylko dwie insercje bez wstawki-insert-update – hazzik

4

Powodem NHibernate robi to w ten sposób dlatego, że:
Gdy zapisuje szczegół to wie tylko o rzeczy wie o szczegóły. Zatem wszelkie odniesienia wzorca, które występują w tle, są ignorowane. Tylko po zapisaniu wzorca widzi powiązanie i aktualizuje elementy kolekcji o identyfikatorze wzorca.
Co jest logicznym z punktu widzenia obiektowego. Jednak z punktu widzenia oszczędności jest nieco mniej logiczne. Przypuszczam, że zawsze możesz zgłosić raport o błędzie lub sprawdzić, czy mógł on już zostać zgłoszony i poprosić o zmianę. Ale przypuszczam, że mają swoje konkretne powody (projekt/domena).

31

NH3 i powyżej pozwalają skorygować zapisać podmioty w przypadku jednokierunkową jeden-do-wielu mapowania bez irytujących save null - save - update cyklu, jeśli ustawisz zarówno not-null="true" na < klucza> i inverse="false" na < jednej-to- wiele>

kod FluentNhibernate urywek za to:

public class MasterMap : ClassMap<Master> 
{ 
    public MasterMap() 
    { 
     Id(x => x.MasterId); 
     Map(x => x.Name); 
     HasMany(x => x.Details) 
      .Not.Inverse()  //these options are very 
      .Not.KeyNullable() //important and work only if set together 
      .Not.KeyUpdate() //to prevent double update 
      .Cascade.All(); 
    } 
} 
+1

Czy jesteś pewny, że nie wydaje powtarzalnej aktualizacji? Skonfigurowałem mapowanie tak, jak opisano i poprawnie ustawia klucz obcy na wstawce (w przeciwieństwie do wstawiania wartości null), ale następnie wykonuje dodatkową aktualizację bazy danych, w której resetuje klucz obcy do tej samej wartości, której użył we wkładce. Wygląda na to, że VikciaR przeżywa, a kilka innych (na podstawie upvotes) doświadcza tego samego. – Sam

+3

@Sam zestaw również '.Not.KeyUpdate()' i podwójna aktualizacja znikną – hazzik

+1

kwerendy działają zgodnie z oczekiwaniami, ale nhibernate nadal tworzy kolumnę na db, która dopuszcza wartości zerowalne? Czy to normalne? – nemenos

Powiązane problemy