2010-11-05 18 views
5

Tengo una clase de dominio que se ve así. Quiero NHibernate a guardar el valor actual de LastUpdate al insertar/actualizar para poder usarlo en las consultas, pero ignorarlo cuando recupero un Foo de la base de datos y dejar que el objeto recalcule el valor cuando realmente tengo acceso a él.Asignación de una propiedad de solo lectura sin setter con Fluidez NHibernate

public class Foo { 
    public DateTime LastUpdate { 
     get { 
      /* Complex logic to determine last update by inspecting History */ 
      return value; 
     } 
    } 
    public IEnumerable<History> History { get; set; } 
    /* etc. */ 
} 

Mi mapeo para Foo se ve así:

public class FooMap : ClassMap<Foo> { 
    Map(x => x.LastUpdate) 
     .ReadOnly(); 
    HasMany(x => x.History); 
    // etc... 
} 

pensé que ReadOnly() era lo que quería lograr esto, pero cuando trato de crear una SessionFactory consigo la siguiente excepción:

Error: FluentNHibernate.Cfg.FluentConfigurationException: An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail.
---> NHibernate.PropertyNotFoundException: Could not find a setter for property 'LastUpdate' in class 'Foo'.

La propiedad no tiene un setter porque no se debe establecer, solo lee de. ¿Es correcto ReadOnly() aquí? Si no, ¿qué?

(v3.0b1 NHibernate, Fluido v1.1 NHibernate)

+0

El ReadOnly() ; solo establece en la correlación mapeada xml las secuencias insert = "false" y la actualización = "false" de la propiedad LastUpdate. – tolism7

Respuesta

12

ReadOnly instruye Fluido NHibernate no busca cambios en esta propiedad, esto no equivale a una propiedad de solo lectura en compiler-world. Su propiedad no es de solo lectura en los ojos de NHibernate porque espera que se llene desde su base de datos. Lo que debe hacer es decirle a NHibernate que debe acceder al valor de esa propiedad a través de un campo privado con el mismo nombre (en minúscula) que la propiedad.

Map(x => x.LastUpdate) 
    .Access.Field(); 

Hay varias alternativas al uso de Field, que uno que utilice dependerá de cómo asignar nombres a los campos privados.

+2

En realidad, no quiero que la propiedad se rellene desde la base de datos, sino que se calcula dinámicamente en el getter. Solo quiero que se guarde en la base de datos para poder consultarlo. –

+6

Si Nhibernate no lo rellena, no sabrá guardarlo porque no tiene idea si y cuando cambia el valor. Ambas soluciones ofrecidas son exactamente iguales y hacen lo que usted describió. NHibernate puede acceder a la variable por campo para que no necesite un setter. Cuando accede al getter, el valor se calculará dinámicamente. Cuando actualice NHibernate guardará el valor. El hecho de que NHibernate lo rellene desde el DB debe ser irrelevante; hasta que acceda no lo sepa/se preocupe, cuando acceda, se calculará el valor. Mire como "inicializado" por Nhibernate si ayuda. – Sisyphus

+0

@Sisyphus Esa explicación ayuda mucho. Gracias. –

2

Por lo que va NHibernate, se puede asignar a un campo, es decir de manera variable miembro Nhibernate puede acceder a la variable miembro directamente. De modo que puede crear una variable miembro como _lastUpdate que se puede asignar directamente. Nhibernate ahora tendrá una variable para usar y puede controlar el valor por separado en su getter porque NHibernate ya no usará el getter de propiedad. Guardará el valor y lo recuperará también, pero el valor recuperado no debería importar porque, tan pronto como acceda a través de su buscador, puede volver a calcularlo. Lo mismo ocurre con las variables privadas sin getters o setters.

En una hbm regular, simplemente asignaría access = field. Todos lo hacen. Aparentemente fluida no es simple. No consumo Fluido ...

EDITAR ...

encontrar cualquiera que sea el objetivo aparentemente siempre en movimiento para los campos de respaldo privados de mapeo está en su versión y el uso que ...

+1

Es tan simple en Fluirte NHibernate: 'Map (x => x.LastUpdate) .Access.Field() ' –

0

Sólo tiene que añadir una incubadora privada vacío a su clase:

 private set { } 

También agrego un atributo y un comentario para documentar mi intención (y hacer ReSharper feliz):

 [UsedImplicitly] 
     // ReSharper disable once ValueParameterNotUsed 
     private set { } 
Cuestiones relacionadas