2009-04-21 22 views
12

Tengo una entidad asignada, Materia, que tiene un componente asignado, Lesión.Asignación de componente NHibernate - Componente nulo

La única propiedad en la lesión es DateOfInjury, que es una fecha de vencimiento nulo.

Cuando recupero la materia, si DateOfInjury es nulo, el componente es nulo.

Por lo tanto, algo así como this.Injury.DateOfInjury tirará.

¿Podría alguien explicar si estoy haciendo algo obvio para causar este comportamiento?

Hubiera esperado que el componente Lesiones fuera inicializado por nHibernate como un objeto y que la propiedad DateOfinjury sea nula.

Esto sería más flexible, ¿no crees?

+2

Puede valer la pena aprovechar el sistema Interceptor/Evento NHibernate para llamar a un inicializador Postload en su objeto Materia para inicializar un miembro Lesión si es nulo. Esto sangra un poco en su capa de negocios, pero se puede minimizar (puede hacer que el inicializador sea un método interno estático en Matter, por ejemplo) – fostandy

Respuesta

9

Creo que ese es el comportamiento predeterminado para una asignación de componentes. Los documentos de NHibernate para componentes dicen que si todos los elementos del componente son nulos, el componente en sí mismo será nulo.

Si solo tiene una sola propiedad en el componente, podría tener sentido simplemente asignarla como una propiedad DateTime que se puede anular en la clase Matter.

+0

Lo suficiente, el componente finalmente tendrá más propiedades. Creo que sería bueno si el componente no fuera nulo, si todas las propiedades son datos opcionales, id tiene que hacer una comprobación nula para atender el comportamiento de los nhibernates. –

+0

Estoy de acuerdo, ese comportamiento es un poco extraño. Hubiera esperado que hiciera lo que estabas diciendo. Sin embargo, creo que tiene sentido, le ahorra a Hibernate la creación de un objeto adicional cuando no hay nada que poner en él. –

5

También me encontré con el mismo problema de esperar que NHibernate inicialice mi componente incluso si todos sus miembros son nulos en la base de datos. Mi motivación detrás de esta implementación fue mover tanta lógica con respecto a mi componente en el componente, sin tener que lidiar con que sea nulo o no.

Gracias a esta publicación, mi búsqueda de una explicación de por qué fallaban mis pruebas de unidad para todos los valores nulos dentro del componente era corta. He arreglado esta pieza en el rompecabezas mediante la ampliación de la auto-propiedad de mi clase de componente ArrivalDay y la asignación de un nuevo caso a mí mismo cuando se asigna nulo:

private ArrivalDay _arrivalDay; 
public ArrivalDay ArrivalDay 
{ 
    get { return _arrivalDay; } 
    set { _arrivalDay = value ?? new ArrivalDay(); } 
}

Esto funciona como un encanto y significa muy poca sobrecarga de la clase que contiene .

+5

El único problema aquí: esto crea problemas para NHibernate al rastrear los componentes. Obtendrá un 'objeto hace referencia a una instancia transitoria no guardada' una vez que intente eliminar la instancia – Tigraine

2

he resuelto esto añadiendo esta propiedad a mi clase de componente

public virtual bool _LoadAlways { get { return true; } set { } } 
+0

, esto no parece funcionar para mí, ¿esta propiedad también debe asignarse? – sawe

1

Ésta es una solución técnicamente viable. Lo he probado con persistencia y no he producido problemas relacionados con los transitorios.

protected internal virtual Injury NullableInjury {get;set;} 
public virtual Injury Injury 
{ 
    get{return NullableInjury ?? (NullableInjury = new Injury()); 
} 

En Nhibernate asigna tu componente al NullableInjury. Esta solución le permite persistir sin el problema transitorio informado en la solución @Oliver.

0

https://stackoverflow.com/a/11187173/206297 no funcionó para mí, pero sobre la base de que:

public class Injury 
{ 
    // ... 
    private bool dummyFieldToLoadEmptyComponent { get; set; } 
} 

public class MatterMap : ClassMap<Matter> 
{ 
    // ... 
    Component(x => x.Injury, m => 
    { 
     // ... 
     m.Map(Reveal.Member<Injury>("dummyFieldToLoadEmptyComponent")).Formula("1=1").ReadOnly(); 
    }); 
} 

El bit Reveal.Member es sólo para asignar un campo privado en Fluido NHibernate. Queremos que el campo sea privado porque no queremos que esa propiedad esté expuesta como parte de nuestra interfaz pública para el componente. Ver https://github.com/jagregory/fluent-nhibernate/wiki/Mapping-private-properties.Si no te importa tener que pública, podría utilizar el mapeo menos detallado de:

m.Map(x => x.DummyFieldToLoadEmptyComponent).Formula("1=1").ReadOnly(); 

El Formula parte se debe a que en realidad no queremos una columna en nuestra base de datos para esto. NHibernate ejecutará esa fórmula al cargar el componente, y siempre evaluará a verdadero. Elegí 1 = 1 como me imagino que es razonablemente cross-DB.

Sin duda, un truco, pero parece funcionar hasta el momento para cargar componentes vacíos y no ha causado ningún error cuando persisten. Usar con discreción sin embargo.

+0

"Elegí 1 = 1 como me imagino que es razonablemente cross-DB" - resulta que es una mala suposición, ya que no funciona en SQL Server. Solo con '.Formula (" 1 ")' funciona en SQL Server. – ngm