2015-05-01 10 views
6

Jestem nowy w NHibernate i C#, więc proszę bądź łagodny!Minimalny i poprawny sposób na mapowanie jeden-do-wielu z NHibernate

Mam następujące dwa NHibernate podmioty:

Employee 
{ 
    private long _id; 
    private String _name; 
    private String _empNumber; 
    private IList<Address> _addresses; 

    //Properties... 
} 

i

Address 
{ 
    private long _id; 
    private String _addrLine1; 
    private String _addrLine2; 
    private String _city; 
    private String _country; 
    private String _postalCode; 

    //Properties 
} 

i mają one-to-many relację z Employee do Address(każdy pracownika może mieć wiele adresów w swoim rekordzie). Dogodnie ignorując fakt, że więcej niż jeden pracownik może mieszkać pod tym samym adresem.

Rozumiem to z perspektywy obiektów w pamięci (encje NHibernate ). Z czym walczę to pliki odwzorowujące (i zabieram tutaj prosty przykład: ). To, co mam wymyślić do tej pory:

// Intentionally left out XML and <hibernate-mapping> 
// Mappings for class 'Employee'. --> 
<class name="Employee" table="Employees"> 
    <id name="ID"> 
     <generator class="native"> 
    </id> 

    <property name="Name" /> 
    <property name="EmpNumber" /> 

    <bag name="Addresses"> 
     <key column="AddressId" /> 
     <one-to-many class="Address" /> 
    </bag> 
</class> 

i

// Intentionally left out XML and <hibernate-mapping> . 
// Mappings for class 'Address' 
<class name="Address" table="Addresses"> 
    <id name="ID"> 
     <generator class="native"> 
    </id> 

    // Intentionally left out name="Employee" 
    // as I don't have corresponding field in Address entity. 
    <many-to-one class="Employee" column="EmployeeID" cascade="all" /> 

    <property name="AddrLine1" /> 
    <property name="AddrLine2" /> 
    <property name="City" /> 
    <property name="Country" /> 
    <property name="PostalCode" /> 
</class> 
  1. Czy jest to prawidłowe?
  2. Jeśli nie, wydaje mi się, że brakuje tutaj pola w jednostce Address , które jest odniesieniem do odpowiedniej jednostki Employee. Ale jeśli tak, to nie mogę zrozumieć, dlaczego jest to konieczne: Nie trzeba sprowadzić Address z Employee, okrągły tylko w drugą stronę ...
+0

Wydaje mi się, że potrzebujesz tutaj wielu do wielu relacji, a nie jednego do wielu, jeśli adresy są unikalne w tabeli adresów. Oznaczałoby to wiele do wielu tabel, które przechowują identyfikator pracownika i identyfikator adresu. W ten sposób pracownik może być powiązany z jednym lub kilkoma adresami, a adres może należeć do więcej niż 1 pracownika. –

+0

@ColeW Nie chcę, aby adresy należały do ​​więcej niż jednego pracownika. To jest celowe. – markvgti

+0

Jeśli to prawda, musisz dodać identyfikator pracownika w tabeli adresowej, aby określić, które adresy należą do których pracowników. W tabeli adresów może istnieć wiele adresów o tym samym identyfikatorze pracownika. W ten sposób nhibernate będzie wiedział, jak wypełnić 'private IList

_addresses;' w obiekcie 'Employee'. Sugerowałbym również, abyś miał obiekt 'Employee' jako część obiektu' Address', ponieważ nawigacja po obu stronach relacji często jest przydatna, nawet jeśli niekoniecznie ma sens z perspektywy logiki biznesowej przez cały czas. –

Odpowiedz

6

Wystarczy kilka wskazówek, podsumowując norm najodpowiedniejszych dowiedziałem się podczas pracy z NHibernate.

1) Jeżeli jest dwukierunkowy referencyjna persitence (kolumna DB) wyrażają w kodzie C#dwukierunkowy również.

Innymi słowy, jeśli dziecko ma odniesienie do rodzica, rodzica powinny mieć odniesienie do dziecka.

public class Employee 
{ 
    ... 
    public virtual IList<Address> { get; set; } 
} 
public class Address 
{ 
    ... 
    public virtual Employee Employee { get; set; } 
} 

Reprezentuje domenę biznesową bez zmian. Adres należy do pracownika i pracownika należy do adresu.

Jeśli z jakichś powodów naprawdę chcemy ograniczyć, że powinniśmy raczej protected modyfikator, ale nadal zachować odniesienie w C#

2) Użyj inverse="true". To może być stosowany tylko wtedy, gdy mamy odwzorowane obie strony (jak wyżej) i doprowadzi do bardziej „oczekiwanych i zoptymalizowanych” INSERT i UPDATE scritps

Czytaj więcej tutaj:

inverse = “true” example and explanation przez mkyong

3) Użyj mapowania pobierania wsadowego prawie zawsze. Pozwoli to uniknąć problemów 1 + N podczas odpytywania. Czytaj więcej:

few details about batch fetching

4) W przypadku, że jeden obiekt (in our case Employee) jest root(inny nie robi tak wiele sensu bez niego) - stosowanie kaskadowy. Czytaj więcej:

nhibernate - Create child by updating parent, or create explicitly?

Rules 2,3,4 za fragmentów mapowania:

<class name="Employee" ... batch-size="25"> 
    ... 
    <bag name="Addresses" 
     lazy="true" 
     inverse="true" 
     batch-size="25" 
     cascade="all-delete-orphan" > 
    // wrong! This columns is the same as for many-to-one 
    //<key column="AddressId" /> 
    // it is the one column expressing the relation 
    <key column="EmployeeId" /> 
    <one-to-many class="Address" /> 
    </bag> 

<class name="Address" ... batch-size="25"> 
    ... 
    <many-to-one not-null="true" name="Employee" column="EmployeeID" /> 

3) jeśli używamy inverse="true nie zapomnij przypisać obu stron stosunku (głównie podczas krytycznego tworzenie)

powodem jest:

instruujemy NHibernate - druga strona jest odpowiedzialna za utrzymywanie relacji. Ale aby to zrobić poprawnie, to musi mieć odniesienie do Employee - aby móc utrzymać swój identyfikator w swojej kolumnie w tabeli Adres.

więc powinno to być standardowy kod aby utworzyć nowy adres

Employee employee = ... // load or create new 
Address address = new Address 
{ 
    ... 
    Employee = employee, // this is important 
}; 
Employee.Addresses.Add(address); 
session.SaveOrUpdate(employee); // cascade will trigger the rest 

Możemy również wprowadzić pewne metody jak AddAddress() który będzie ukryć tę złożoność, ale ustawienie obu stron jest dobrym prectice.

+0

Czy NHibernate działa dokładnie tak samo z C#, jak Hibernacja ma z Javą? Pytam, ponieważ artykuł na mkyong.com o 'inverse =" true "' używa przykładów Java. – markvgti

+0

Ten fragment kodu jest taki sam (został przeniesiony z Java do C#). Najważniejszy jest "duch odwrotności". Tak więc, nawet gdyby wystąpiły jakiekolwiek niewielkie różnice, koncepcja jest taka sama. Mam nadzieję, że to pomaga;) Ciesz się potężnym NHibernate;) –

1

Należy dodać kaskadę all-delete-orphan w relacji one-to-many, jeśli usuniesz Employee, adres zostanie również usunięty.

Jeśli nie trzeba Employee odniesienie stworzyć inverse=false relację takiego: here

Powiązane problemy