2010-12-16 7 views
18

Estoy tratando de establecer una relación de la siguiente manera. Cada elemento principal tiene una o más Detalle artículos:Configuración de NHibernate para la relación uno a varios unidireccional

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

y las asignaciones:

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

El Maestro mesa base de datos es:

masterId uniqueidentifier NOT NULL 
name  nvarchar(max) NULL 

y Detalle es:

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

Realmente no me importa tener un enlace desde Detalle volver al Maestro - en otras palabras, objetos de información por sí mismas no son sólo interesante para mi capa de dominio. Se siempre acceder a través de su objeto maestro.

El uso de código como este:

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

Esto funciona muy bien, excepto por una limitación loca indica en this post: NHibernate hace un INSERT y pone Detail.MasterId como NULL en primer lugar, a continuación, no una actualización de la puso a el verdadero MasterId.

Realmente, no quiero entradas de detalles con NULL MasterIds, así que si configuro el campo MasterId en NOT NULL, el INSERT to Detail fallará, porque como he dicho, NHibernate intenta poner MasterId = NULL.

Creo que mi pregunta se reduce a esto:

¿Cómo puedo obtener el ejemplo de código anterior para trabajar con mi modelo de dominio existente (por ejemplo, sin añadir una propiedad Detail.Master), y el campo Detail.MasterId en la base de datos establecida en NOT NULL?

¿Hay alguna manera de hacer que Nhibernate simplemente ponga el MasterId correcto en el INSERT inicial, en lugar de ejecutar una ACTUALIZACIÓN luego? ¿Hay alguna razón en algún lugar para esta decisión de diseño? - Estoy luchando para ver por qué se haría de esta manera.

Respuesta

14

No puede. Para citar el enlace desde my answer en la otra pregunta se enlazó a:

Muy Importante Nota: Si la columna <key> de una asociación <one-to-many> está declarada NOT NULL, NHibernate puede causar violaciónes de restricción cuando se crea o actualiza el asociación. Para evitar este problema, debe usar una asociación bidireccional con los muchos extremos valorados (el conjunto o la bolsa) marcados como inverse="true". Vea la discusión de asociaciones bidireccionales más adelante en este capítulo.

Editar: como Hazzik ha señalado con razón, esto ha cambiado en NHibernate 3 y superior.Los documentos lamentablemente no se han actualizado, así que aquí está Hazzik:

[Si] configurar inverse="false" y not-null en <key>, NH3 y por encima llevará a cabo sólo dos insertos INSEAD de inserción-inserción-actualización.

+0

me leyó eso, sino que en realidad no explica nada (tampoco lo hace la discusión de las asociaciones bidireccionales referencia). ¿Hay una razón detrás de esta decisión? ¿Es una limitación de diseño de nhibernate? ¿Es un error? Como relativamente novato en nhibernate, y sin saber nada de los elementos internos, parece que esto debería ser posible. – gregmac

+0

Honestamente, no sé. No está clasificado como un error por el equipo de NHibernate, es solo un efecto secundario de cómo NHibernate persiste a las entidades. No voy a pretender saber las razones, pero me imagino que tiene algo que ver con ser agnóstico de base de datos y generador de identidades. –

+4

En realidad, si se establece inverse = "false" y no-null en la clave NH3 y superior, solo se realizarán dos inserciones insead de insert-insert-update – hazzik

4

La razón NHibernate lo hace de esta manera es porque:
Cuando se guarda el detalle que sólo sabe acerca de las cosas el detalle conoce. Por lo tanto, se ignoran las referencias principales que se producen en segundo plano. Solo cuando se guarda el máster, ve la relación y actualiza los elementos de la colección con el ID del máster.
Cuál es desde un punto de vista orientado a objetos lógico. Sin embargo, desde un punto de vista de ahorro es un poco menos lógico. Supongo que siempre puede presentar un informe de error o ver si ya se ha archivado y pedirle que lo modifique. Pero supongo que tienen sus razones específicas (diseño/dominio).

31

NH3 y anteriormente permiten corregir salvar a las entidades en caso de uno-a-muchos mapeo unidireccional sin molestar a save null - save - ciclo update, si se establece tanto en not-null="true" < tecla> y inverse="false" en < de uno a muchos>

fragmento de código para ese FluentNHibernate:

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

¿Estás seguro de que no emite una actualización repetitiva? Configuré mi asignación como se describe y establece la clave externa correctamente en la inserción (en lugar de insertar nulo), pero luego realiza una actualización de base de datos adicional donde restablece la clave externa al mismo valor que utilizó en la inserción. Parece que VikciaR está experimentando y un par de otros (basados ​​en upvotes) están experimentando lo mismo. – Sam

+3

@Sam establecido también '.Not.KeyUpdate()' y la doble actualización se habrá ido – hazzik

+1

las consultas funcionan como se esperaba, pero ¿nhibernate todavía crea una columna en la base de datos que permite valores que aceptan valores? ¿Esto es normal? – nemenos

Cuestiones relacionadas