2009-02-15 8 views
14

Estoy tratando de usar NHibernate con una base de datos existente. En el modelo de datos, hay columnas en cada tabla que contienen la hora y el nombre de usuario de la última actualización realizada en una fila. ¿Cómo hago esto usando NHibernate?¿Cómo implemento las columnas ChangeTime y ChangeUser usando NHibernate?

Intenté implementar un interceptor que establezca ChangeTime y ChangeUser en las entidades antes de que se guarde con el método IInterceptor.OnSave. Esto no funcionó porque la configuración de estas propiedades desencadena una actualización de la fila, incluso si no se han modificado otras propiedades.

Podría haber funcionado si hubiera alguna manera de decirle a NHibernate que excluyera las propiedades ChangeTime y ChangeUser, luego lo hace con comprobación sucia. Pero no he encontrado ninguna forma de lograr esto.

Gracias por cualquier ayuda.

Respuesta

14

Debe registrar un agente de escucha en el preinserto y preactualizar los eventos. Puede hacerlo a través de la configuración de este modo:

<hibernate-configuration> 
    ... 
    <event type="pre-update"> 
     <listener class="MyListener, MyAssembly"/> 
    </event> 
    <event type="pre-insert"> 
     <listener class="MyListener, MyAssembly"/> 
    </event> 
</hibernate-configuration> 

y luego implementar un oyente - algo como esto (podría no ser del todo exacto - por escrito de mi memoria):

public class MyListener : IPreUpdateEventListener, IPreInsertEventListener 
{ 
    public bool OnPreUpdate(PreUpdateEvent evt) 
    { 
     if (evt.Entity is IHasLastModified) 
      UpdateLastModified(evt.State, evt.Persister.PropertyNames); 

     return false; 
    } 

    public bool OnPreInsert(PreInsertEvent evt) 
    { 
     if (evt.Entity is IHasLastModified) 
      UpdateLastModified(evt.State, evt.Persister.PropertyNames); 

     return false; 
    } 

    void UpdateLastModified(object[] state, string[] names) 
    { 
     var index = Array.FindIndex(names, n => n == "LastModified"); 

     state[index] = DateTime.Now; 
    } 
} 

y hacer lo mismo cosa con el evento pre actualización.

EDITAR: Esta se encarga de insertar y actualizar y parece funcionar.

+0

Gracias! Muy buena respuesta, me ayudó mucho. Este método no modifica las propiedades de las entidades, solo lo que se escribe en la base de datos. Pero parece que no hay problema para establecer las propiedades de la entidad al mismo tiempo. –

+3

Para obtener una solución más completa a este problema exacto, consulte http://ayende.com/Blog/archive/2009/04/29/nhibernate-ipreupdateeventlistener-amp-ipreinserteventlistener.aspx – mookid8000

+4

Según la publicación de blog de Ayende, es necesario actualizar el objeto de la entidad (evt.Entity) Y el estado. –

1

respuesta de Mookid es correcta aunque me gustaría señalar que si uno está utilizando S # arp Arquitectura, la configuración NHib debe establecerse de la siguiente manera:

<hibernate-configuration> 
    <session-factory> 
    ... 
     <event type="pre-update"> 
      <listener class="MyListener, MyAssembly"/> 
     </event> 
     <event type="pre-insert"> 
      <listener class="MyListener, MyAssembly"/> 
     </event> 
    </session-factory> 
</hibernate-configuration> 

Los elementos de suceso entran en la sesión- elemento de fábrica.

5

Hey, yo sólo tenía que resolver esto en un proyecto que estoy trabajando, aquí está mi respuesta

public interface IDateModified 
{ 
    DateTime Created { get; set; } 
    DateTime Modified { get; set; } 
} 

public class CustomDefaultSaveOrUpdateEventListener 
    : DefaultSaveOrUpdateEventListener 
{ 
    protected override object EntityIsPersistent(SaveOrUpdateEvent evt) 
    { 
     var entity = evt.Entity as IDateModified; 
     if (entity != null) 
     { 
       entity.Modified = DateTime.Now; 
     } 

     return base.EntityIsPersistent(evt); 
    } 

    protected override object EntityIsTransient(SaveOrUpdateEvent evt) 
    { 
     var entity = evt.Entity as IDateModified; 
     if (entity != null) 
     { 
      entity.Created = entity.Modified = DateTime.Now; 
     } 

     return base.EntityIsTransient(evt); 
    } 
} 

Luego, en la configuración de mi (estoy usando Fluido NHibernate para configurar mis pruebas unitarias en el código)

configuration.EventListeners.SaveOrUpdateEventListeners 
= new ISaveOrUpdateEventListener[] 
{ 
    new CustomDefaultSaveOrUpdateEventListener() 
}; 

AWESOMENESSSSSSSSS!

+0

No funcionó para mí. Agrego un comentario en tu blog. – dariol

Cuestiones relacionadas