2010-12-16 16 views
18

Sto provando ad impostare una relazione come segue. Ogni Maestro elemento ha uno o più Particolare articoli:Configurazione NHibernate per la relazione unidirezionale unidirezionale

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

e mappature:

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

La Maestro tabella di database è:

masterId uniqueidentifier NOT NULL 
name  nvarchar(max) NULL 

e Particolare è:

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

Non mi importa di avere un link da Dettaglio di nuovo al Maestro - in altri termini, gli oggetti del particolare da sole non sono solo interessanti per il mio livello di dominio. Saranno sempre accessibili tramite il loro oggetto Master.

Utilizzando il codice come questo:

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(); 
} 

Questa grande opera, ad eccezione di una limitazione folle delineato nella this post: NHibernate fa un INSERT e mette Detail.MasterId come NULL, poi fa un aggiornamento per impostarlo su il vero MasterId.

In realtà, non voglio le voci di dettaglio con NULL MasterIds, quindi se imposto il campo MasterId su NOT NULL, l'INSERT to Detail fallirà, perché come ho detto NHibernate sta cercando di inserire MasterId = NULL.

Credo che la mia domanda si riduce a questo:

Come posso ottenere il codice di esempio sopra per lavorare con il mio modello di dominio esistente (ad esempio, senza l'aggiunta di una proprietà Detail.Master), e il campo Detail.MasterId nel database impostato su NOT NULL?

C'è un modo per ottenere Nhibernate per inserire semplicemente il MasterId corretto nell'INSERT iniziale, piuttosto che eseguire un UPDATE in seguito? C'è una motivazione da qualche parte per questa decisione di progettazione? - Sto facendo fatica a capire perché sarebbe stato fatto in questo modo.

risposta

14

Non è possibile. Per citare il link dal my answer d'altra domanda si è collegato al:

nota molto importante: Se la colonna <key> di un'associazione <one-to-many> NON è dichiarato nullo, NHibernate può causare violazioni di vincoli quando si crea o aggiorna il associazione. Per evitare questo problema, è necessario utilizzare un'associazione bidirezionale con l'estremità con molti valori (l'insieme o il sacchetto) contrassegnata come inverse="true". Vedi la discussione delle associazioni bidirezionali più avanti in questo capitolo.

Edit: come Hazzik ha giustamente sottolineato, questo è cambiato in NHibernate 3 e superiori.La documentazione purtroppo non sono state aggiornate, quindi ecco Hazzik:

[Se] imposta inverse="false" e not-null su <key>, NH3 e soprattutto si esibiranno solo due inserti INSEAD di inserto-insert-update.

+0

ho letto, ma in realtà non spiega nulla (neppure la discussione di associazioni bidirezionali riferimento). C'è una logica dietro questa decisione? E 'una limitazione del design di Nhibernate? E 'un errore? Essendo un principiante inesperto, e non conoscendo affatto gli interni, sembra che questo dovrebbe essere possibile .. – gregmac

+0

Onestamente, non lo so. Non è classificato come un bug dal team di NHibernate, è solo un effetto collaterale di come l'NHibernate persiste nelle entità. Non farò finta di conoscere le ragioni, ma immagino che abbia qualcosa a che fare con l'essere agnostico di database e generatore di identità. –

+4

In realtà se impostato inverse = "false" e not-null sulla chiave NH3 e sopra eseguirà solo due inserti insead di insert-insert-update – hazzik

4

Il motivo per NHibernate lo fa in questo modo è perché:
Quando si salva dettaglio si conosce solo la roba dettaglio conosce. Quindi tutti i riferimenti principali che si verificano in background vengono ignorati. Solo quando il master viene salvato vede la relazione e aggiorna gli elementi della collezione con l'id del master.
Quale è da un punto di vista orientato agli oggetti logico. Tuttavia da un punto di vista del risparmio è leggermente meno logico. Suppongo che tu possa sempre presentare una segnalazione di bug, o guardare se potrebbe essere già stata archiviata e chiedere loro di cambiarla. Ma suppongo che abbiano i loro specifici motivi (design/dominio).

31

NH3 e soprattutto consentono di correggere salvare le entità in caso di uno-a-molti mappatura unidirezionale, senza fastidiosi save null - save - ciclo update, se si imposta sia not-null="true" su < tasto> e inverse="false" su < one-to- molti>

codice FluentNHibernate snippet che:

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

Sei sicuro di non rilasciare un aggiornamento ripetitivo? Ho impostato la mia mappatura come delineato e imposta correttamente la chiave esterna sull'inserto (a differenza dell'inserimento di null), ma poi esegue un aggiornamento del database aggiuntivo in cui reimposta la chiave esterna allo stesso valore utilizzato nell'inserto. Sembra che VikciaR stia vivendo e un altro paio (basato su upvotes) sta vivendo la stessa cosa. – Sam

+3

@Sam imposta anche '.Not.KeyUpdate()' e il doppio aggiornamento è terminato. Le query – hazzik

+1

funzionano come previsto, ma nibernate crea ancora una colonna sul db che consente valori nullable? È normale? – nemenos

Problemi correlati