2015-05-01 12 views
6

Sono nuovo di NHibernate e C#, quindi per favore sii gentile!Modo minimo e corretto per mappare uno-a-molti con NHibernate

ho le seguenti due entità NHibernate:

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

    //Properties... 
} 

e

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

    //Properties 
} 

e hanno un rapporto one-to-manyEmployee-Address(ogni dipendente può avere più indirizzi nella loro record). Ignorando comodamente il fatto che più di un dipendente possa risiedere allo stesso indirizzo.

Lo capisco dal punto di vista degli oggetti in memoria (le entità di NHibernate ). Quello a cui sono alle prese sono i file di mappatura (e sto prendendo un esempio semplice qui). Questo è quello che sono venuto in mente finora:

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

e

// 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. È corretto?
  2. In caso contrario, sembra che quello che mi manca qui è un campo nell'entità che è un riferimento all'entità Employee corrispondente. Ma se è così, allora non posso capire perché questo è necessario: non ho bisogno di andare a prendere un Address da un Employee, solo il contrario ...
+0

Mi sembra che sia necessaria una relazione molti a molti qui e non uno a molti se gli indirizzi sono univoci nella tabella degli indirizzi. Ciò significherebbe una tabella molti a molti che memorizza un ID dipendente e un ID indirizzo. In questo modo un dipendente può essere collegato a uno o più indirizzi e l'indirizzo può appartenere a più di 1 dipendente. –

+0

@ColeW Non voglio che gli indirizzi appartengano a più di un dipendente. Questo è intenzionale. – markvgti

+0

Se ciò è vero, è necessario aggiungere un ID dipendente nella tabella degli indirizzi per identificare quali indirizzi appartengono a quali dipendenti. Quindi possono esistere più indirizzi nella tabella indirizzi con lo stesso ID dipendente. Questo è il modo in cui nhibernate sarebbe in grado di riempire gli "indirizzi privati ​​IList

" nell'oggetto 'Dipendente'. Suggerirei anche di avere un oggetto 'Employee' come parte dell'oggetto' Address' dato che la navigazione su entrambi i lati della relazione spesso è utile anche se non ha necessariamente senso da una prospettiva di business logic per tutto il tempo. –

risposta

6

Solo qualche accenno, che riassume le norme più adatte ho scoperto quando si lavora con NHibernate.

1) Se c'è una riferimento bidirezionale in persitence (colonna DB), esprimere in C# codice bidirezionale pure.

altre parole, se un bambino ha riferimento al genitore, genitore dovrebbero avere riferimento a bambino.

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

Rappresenta il dominio aziendale così com'è. L'indirizzo appartiene al Dipendente e il Dipendente appartiene all'indirizzo.

Se per qualche motivo vogliamo davvero limitare tale, dovremmo piuttosto protected modificatore, ma ancora mantenere il riferimento in C#

2) Utilizzare inverse="true". Questo potrebbe essere utilizzato solo se abbiamo mappato entrambi i lati (come sopra), e porterà a più "attesi e ottimizzati" INSERISCI e UPDATE scritps

maggiori qui:

inverse = “true” example and explanation da mkyong

3) Utilizza la mappatura di raccolta batch quasi ovunque. Ciò eviterà problemi 1 + N durante l'interrogazione. Per saperne di più:

few details about batch fetching

4) Nel caso in cui, che un oggetto è (in our case Employee)root(l'altro non fa così molto senso senza di essa) - utilizzo a cascata. Per saperne di più:

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

Regole 2,3,4 in una mappatura frammenti:

<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) se usiamo inverse="true non dimenticate di assegnare entrambi i lati della relazione (per lo più critica durante creazione)

Il motivo è:

si ordina a NHibernate - l'altro lato (Address) è responsabile della relazione persistente. Ma per farlo correttamente, è necessario che Address abbia riferimento a Employee - per poter mantenere il suo ID nella sua colonna nella tabella Indirizzi.

quindi questo dovrebbe essere il codice standard per creare nuovo indirizzo

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 

Possiamo anche introdurre qualche metodo come AddAddress() che nasconde questa complessità, ma l'impostazione entrambe le parti è un buon prectice.

+0

NHibernate funziona esattamente allo stesso modo con C# come fa Hibernate con Java? Chiedo perché l'articolo su mkyong.com su 'inverse =" true "' sta usando esempi Java. – markvgti

+0

Questo pezzo di codice è lo stesso (è stato portato da Java a C#). Il più importante è lo "spirito dell'inverso". Quindi, anche se ci sarebbero piccole differenze, il concetto è lo stesso. Spero che aiuti;) Godetevi il potente NHibernate;) –

1

Si dovrebbe aggiungere la cascata all-delete-orphan nella relazione one-to-many, se si cancella lo Employee anche l'indirizzo verrà eliminato.

Se non avete bisogno di Employee riferimento creare una relazione inverse=false come questo: here