NHibernate y el patrón State

Este es un ejemplo de como persistir con NHibernate una propiedad cuyo tipo de dato es otra clase no persistente, en este caso el Estado de un Evento.

El dominio

Domain

En este dominio el único objeto que se persiste es Evento, el mismo tiene una propiedad Estado de tipo EventoState que es una clase abstracta cuyas posibles implementaciones son las que se ven heredando de esta.

Para el caso del estado no seteado contamos con la clase EventoNullState que tiene el comportamiento correspondiente a este estado del evento:

public virtual EventoState Estado
{
    get { return _estado ?? EventoNullState.GetInstance(); }
    set { _estado = value; }
}

Objetivo

Persistir en una columna de la tabla Evento el Estado que tiene el objeto y que cuando este sea recuperado de la base de datos se cargue el Estado correspondiente.

Persistencia

Para configurar NHibernate utilizamos ConfOrm de la siguiente manera:

var orm = new ObjectRelationalMapper();
orm.TablePerClass<Evento>();

orm.Complex<Evento>(e => e.Estado);

var mapper = new Mapper(orm);
mapper.AddPropertyPattern(p => p.DeclaringType == typeof(Evento) && p.Name == "Estado", a => a.Type<EventoStateType>());

como podemos observar, definimos un patrón para la propiedad Estado diciendo que utilice una instancia de tipo EventoStateType para pasar de objeto a base de datos o viceversa. En esta clase estamos extendiendo la clase GenericWellKnownInstanceType que podemos referenciar desde unhaddins o simplemente tomarla “prestada” (haga clic aquí para ver la clase original) ya que esta clase no depende de otras.

EventoStateType

public class EventoStateType : GenericWellKnownInstanceType<EventoState, string> 
{
    public static IEnumerable<EventoState> All
    {
        get
        {
            return new[]
                   {
                       EventoNullState.GetInstance(), EventoPropuestoState.GetInstance(), EventoAgendadoState.GetInstance(),
                       EventoConfirmadoState.GetInstance(), EventoPublicadoState.GetInstance(), EventoCanceladoState.GetInstance(),
                       EventoDescartadoState.GetInstance()
                   };
        }
    }

    public EventoStateType()
        : base(All, (state, id) => state.Descripcion == id, state => state.Descripcion)
    {
    }

    public override SqlType[] SqlTypes
    {
        get { return new[] {SqlTypeFactory.GetString(25)}; }
    }
}

En el constructor de EventoStateType podemos observar la llamada al constructor de GenericWellKnownInstanceType al que le pasamos los siguientes valores:

    All Una lista con todos los posibles estados.
    (state, id) => state.Descripcion == id una función que será evaluada para relacionar el objeto (state) con su identificador en la base de datos (id).
    state => state.Description una función que, dado un objeto (state), devuelva el identificador con que será persistido.

Y para terminar, en la tabla donde se persiste cada Evento vamos a necesitar un campo con el tipo correspondiente a un string de 25, según SqlTypeFactory.GetString(25) en el cual se persistirá el valor de pa propiedad Descripcion de cada estado.

El código completo podés verlo en el proyecto que estamos desarrollando en la comunidad alt.net hispano para la gestión administrativa de eventos haciendo clic aquí.