8

ho i seguenti 2 classi:Fluent NHibernate Uno-a-molti Mapping

Annuncio

public virtual int Id { get; set; 
public virtual IList<AdvertImage> AdvertImages { get; set; } 

AdvertImage

public virtual int Id { get; set; } 
public virtual string Filename { get; set; 
public virtual Advert Advert { get; set; } 

Nel DB, mio ​​tavolo AdvertImages ha il FK 'AdvertId' che si riferisce alla tabella degli annunci che ha il PK di 'Id'.

Questa è una mappatura uno a molti, in quanto un annuncio può avere molte immagini.

mappature mio Fluent NHibernate (a cura per brevità) sono:

AdvertMap

Id(x => x.Id) 
    .GeneratedBy.Identity(); 
... 
HasMany(x => x.AdvertImages) 
    .KeyColumn("AdvertId") 
    .Inverse(); 
... 
Table("Adverts"); 

AdvertImageMap

Id(x => x.Id) 
    .GeneratedBy.Identity(); 
... 
References(x => x.Advert) 
    .Column("AdvertId"); 
... 
Table("AdvertImages"); 

Sto creando una nuova istanza di Advert nel codice, quindi popolando il prope AdvertImages rty (di Advert) con un List<AdvertImage>.

Quando vado a persistere l'oggetto Advert nel DB, vorrei inserire AdvertImages nella loro tabella AdvertImages, ma a causa della relazione tra le 2 tabelle, ho bisogno che l'inserzione annuncio avvenga prima, quindi come viene generato l'ID PK, che può quindi essere inserito nella tabella AdvertImages. (Quando creo il mio elenco di AdvertImage, sto compilando la proprietà Filename, ma ovviamente non ho il nuovo AdvertId in quella fase, quindi voglio che venga popolato quando l'annuncio è persistente nel DB).

Ho provato a sperimentare con le diverse impostazioni Inverse() e Cascade ma non ci sono ancora riusciti. Qualcuno può aiutare, per favore?

risposta

10

È necessario modificare la mappatura Advert a cascata:

Id(x => x.Id) 
    .GeneratedBy.Identity(); 

HasMany(x => x.AdvertImages) 
    .KeyColumn("AdvertId") 
    .Inverse() 
    .Cascade.AllDeleteOrphan(); 

Table("Adverts"); 

Si dovrebbe quindi essere in grado di fare qualcosa di simile a persistere un oggetto Advert e sono i bambini AdvertImage.

Advert newAdvert = new Advert(); 
AdvertImage newImage = new AdvertImage(); 
newImage.Advert = newAdvert; 
newAdvert.AdvertImages.Add(newImage); 

using(NHibernate.ISession session = SessionFactory.GetCurrentSession()) 
{ 
    using (NHibernate.ITransaction tran = session.BeginTransaction()) 
    { 
     session.Save(newAdvert); 
     tran.Commit(); 
    } 
} 

I miei soggetti di solito contengono Aggiungere e rimuovere i metodi per uno bidirezionale per molti rapporti in questo modo:

public class Advert 
{ 
    public virtual IList<AdvertImage> AdvertImages { get; set; } 

    public virtual void AddImage(AdvertImage newImage) 
    { 
     newImage.Advert = this; 
     AdvertImages.Add(newImage); 
    } 
} 
+0

Grazie a Cole W e un bel suggerimento sui metodi Aggiungi e Rimuovi. – marcusstarnes

1

Quello che per me di solito è impostare la colonna della chiave esterna per consentire i valori nulli in DB: questa sarebbe la colonna AdvertId, ma non sono sicuro che funzioni nel tuo caso, dal momento che stai utilizzando l'identità. Ciò che NHibernate fa è INSERT tutto con una query e quindi aggiorna la colonna della chiave esterna della tabella figlio all'id corretto della tabella genitore. Forse funzionerebbe anche nel tuo caso.

Ecco qualche domanda simile che potrebbe aiutare: Cascade insert on one-to-many with fluent NHibernate

+1

Questo collegamento non ha senso in quanto non ha nulla a che vedere con "Fluent NHibernate". – Komengem

+0

@KomengeMwandila Sebbene la risposta alla domanda che ho collegato non usi Fluent NHibernate, la domanda è. Inoltre, Fluent NHibernate non aggiunge nulla di nuovo qui. Fornisce solo un'altra interfaccia per la mappatura di NHibernate. Una volta compreso il funzionamento della mappatura, è possibile applicarla a Fluent NHibernate, mappatura XML, mappatura tramite codice ... –

2

Ho avuto lo stesso problema. Ho passato un po 'di tempo a provare tutti i diversi tipi di mappatura.Ho poi scoperto che le mie mappature andavano bene e che in realtà dovevo avvolgere la mia sessione in una transazione e utilizzare il metodo Commit() dopo il metodo session.SaveOrUpdate().

using(var session = sessionFactory.OpenSession()) 
using(var tx = session.BeginTransaction()) 
{ 
// execute code that uses the session 
tx.Commit(); 
} 
+0

grazie ..avuto un sacco di tempo a scavare intorno a questo problema –