8

He los siguientes 2 clases:Fluido NHibernate Uno-A-Muchos Mapeo

anuncio

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

En el DB, mi mesa AdvertImages tiene el FK 'AdvertId' que se relaciona con la tabla Anuncios que tiene el PK de 'Id'.

Este es un mapeo Uno a Muchos, en el que un anuncio puede tener muchas imágenes.

asignaciones Mi Fluido NHibernate (editado por brevedad) son:

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

estoy creando una nueva instancia de Advert en el código, luego llenando el propo AdvertImages rty (del anuncio) con un List<AdvertImage>.

Cuando voy a persistir mi objetivo Advert con el PP, me gustaría que los AdvertImages para ser insertado en su mesa AdvertImages, pero debido a la relación entre las 2 mesas, necesito la inserción del anuncio que suceda primero, a fin se genera el identificador PK, que luego se puede insertar en la tabla AdvertImages. (Cuando creo mi lista de AdvertImage, estoy rellenando la propiedad Filename, pero obviamente no tengo el nuevo AdvertId en esa etapa, así que quiero que se llene cuando el anuncio persista en la base de datos).

He intentado experimentar con diferentes configuraciones Inverse() y Cascade, pero todavía no lo he logrado. ¿Alguien puede ayudar, por favor?

Respuesta

10

Es necesario que cambie la asignación de Advert a cascada:

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

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

Table("Adverts"); 

A continuación, debería ser capaz de hacer algo como esto para persistir un objeto Advert y son niños 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(); 
    } 
} 

Mis entidades suelen contener Agregar y quitar métodos para uno bidireccional a muchas relaciones de esta manera:

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

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

Gracias Cole W, y buen consejo sobre los métodos Agregar y Eliminar. – marcusstarnes

1

Lo que a mí me funciona generalmente es configurar la columna de la clave externa para permitir nulos en DB, esa sería su columna AdvertId, pero no estoy seguro de si eso funcionaría en su caso, ya que está usando identidad. Lo que NHibernate hace es INSERTAR todo con una consulta y luego actualiza la columna de la clave externa de la tabla secundaria con la ID correcta de la tabla padre. Quizás también funcionaría en tu caso.

He aquí alguna pregunta similar que podría ayudar: Cascade insert on one-to-many with fluent NHibernate

+1

Ese enlace que incluye no tiene sentido ya que no tiene nada que ver con 'Fluido NHibernate'. – Komengem

+0

@KomengeMwandila Aunque la respuesta a la pregunta que he vinculado no utiliza Fluent NHibernate, la pregunta sí. Además, Fluent NHibernate no agrega nada nuevo aquí. Simplemente proporciona otra interfaz para el mapeo de NHibernate. Una vez que comprenda cómo funciona el mapeo, puede aplicarlo a Fluidez NHibernate, mapeo XML, mapeo por código ... –

2

que tenían el mismo problema. Pasé un tiempo probando todos los tipos diferentes de mapeo.Luego descubrí que mis asignaciones estaban bien y en realidad era que necesitaba envolver mi sesión en una transacción y usar el método Commit() después del método session.SaveOrUpdate().

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

gracias ... hemos ahorrado mucho tiempo investigando este problema –

Cuestiones relacionadas