nhibernate - programa - desactivar actualizaciones windows 10 2018
¿Cómo desactivar el comportamiento de actualización automática(comprobación sucia) de NHibernate? (4)
Acabo de descubrir que si obtengo un objeto de una sesión de NHibernate y cambio una propiedad en un objeto, ¡NHibernate actualizará automáticamente el objeto en la confirmación sin que yo llame a Session.Update(myObj)
!
Puedo ver cómo esto podría ser útil, pero como comportamiento predeterminado parece una locura.
Actualización: ahora entiendo la ignorancia de la persistencia, por lo que este comportamiento es ahora claramente la opción preferida. Dejaré esta pregunta ahora vergonzosa para ayudar a otros usuarios profanos.
¿Cómo puedo evitar que esto suceda? ¿Es este comportamiento predeterminado de NHibernate o algo que viene de AutoPersistenceModel de Fluent NHibernate?
Si no hay manera de detener esto, ¿qué hago? A menos que me esté perdiendo el punto, este comportamiento parece crear un lío correcto.
Estoy usando NHibernate 2.0.1.4 y una compilación Fluent NHibernate del 18/3/2009
¿Este chico tiene razón con su respuesta ?
También he leído que anular una escucha de eventos podría ser una solución para esto. Sin embargo, IDirtyCheckEventListener.OnDirtyCheck
no se llama en esta situación. ¿Alguien sabe qué oyente necesito anular?
Hicimos esto usando los Oyentes del Evento con NH (este no es mi trabajo, pero no puedo encontrar el enlace donde lo hice ...).
Tenemos un EventListener para leer los datos, para establecerlo como ReadOnly - y luego uno para Save (y SaveOrUpdate) para establecerlos como cargados, por lo que ese objeto persistirá cuando llamemos a Save()
manualmente en él.
Eso, o podría usar una sesión IStatelessSession que no tiene seguimiento de estado / cambio.
Esto establece la entidad / elemento como ReadOnly inmediatamente al cargar.
Solo he incluido un detector de eventos de inserción, pero mi código de configuración hace referencia a todos ellos.
/// <summary>
/// A listener that once an object is loaded will change it''s status to ReadOnly so that
/// it will not be automatically saved by NH
/// </summary>
/// <remarks>
/// For this object to then be saved, the SaveUpdateEventListener is to be used.
/// </remarks>
public class PostLoadEventListener : IPostLoadEventListener
{
public void OnPostLoad(PostLoadEvent @event)
{
EntityEntry entry = @event.Session.PersistenceContext.GetEntry(@event.Entity);
entry.BackSetStatus(Status.ReadOnly);
}
}
Al guardar el objeto, lo llamamos para establecer ese objeto en Cargado (lo que significa que ahora persistirá)
public class SaveUpdateEventListener : ISaveOrUpdateEventListener
{
public static readonly CascadingAction ResetReadOnly = new ResetReadOnlyCascadeAction();
/// <summary>
/// Changes the status of any loaded item to ReadOnly.
/// </summary>
/// <remarks>
/// Changes the status of all loaded entities, so that NH will no longer TrackChanges on them.
/// </remarks>
public void OnSaveOrUpdate(SaveOrUpdateEvent @event)
{
var session = @event.Session;
EntityEntry entry = session.PersistenceContext.GetEntry(@event.Entity);
if (entry != null && entry.Persister.IsMutable && entry.Status == Status.ReadOnly)
{
entry.BackSetStatus(Status.Loaded);
CascadeOnUpdate(@event, entry.Persister, @event.Entry);
}
}
private static void CascadeOnUpdate(SaveOrUpdateEvent @event, IEntityPersister entityPersister,
object entityEntry)
{
IEventSource source = @event.Session;
source.PersistenceContext.IncrementCascadeLevel();
try
{
new Cascade(ResetReadOnly, CascadePoint.BeforeFlush, source).CascadeOn(entityPersister, entityEntry);
}
finally
{
source.PersistenceContext.DecrementCascadeLevel();
}
}
}
Y lo implementamos en NH así:
public static ISessionFactory CreateSessionFactory(IPersistenceConfigurer dbConfig, Action<MappingConfiguration> mappingConfig, bool enabledChangeTracking,bool enabledAuditing, int queryTimeout)
{
return Fluently.Configure()
.Database(dbConfig)
.Mappings(mappingConfig)
.Mappings(x => x.FluentMappings.AddFromAssemblyOf<__AuditEntity>())
.ExposeConfiguration(x => Configure(x, enabledChangeTracking, enabledAuditing,queryTimeout))
.BuildSessionFactory();
}
/// <summary>
/// Configures the specified config.
/// </summary>
/// <param name="config">The config.</param>
/// <param name="enableChangeTracking">if set to <c>true</c> [enable change tracking].</param>
/// <param name="queryTimeOut">The query time out in minutes.</param>
private static void Configure(NHibernate.Cfg.Configuration config, bool enableChangeTracking, bool enableAuditing, int queryTimeOut)
{
config.SetProperty(NHibernate.Cfg.Environment.Hbm2ddlKeyWords, "none");
if (queryTimeOut > 0)
{
config.SetProperty("command_timeout", (TimeSpan.FromMinutes(queryTimeOut).TotalSeconds).ToString());
}
if (!enableChangeTracking)
{
config.AppendListeners(NHibernate.Event.ListenerType.PostLoad, new[] { new Enact.Core.DB.NHib.Listeners.PostLoadEventListener() });
config.AppendListeners(NHibernate.Event.ListenerType.SaveUpdate, new[] { new Enact.Core.DB.NHib.Listeners.SaveUpdateEventListener() });
config.AppendListeners(NHibernate.Event.ListenerType.PostUpdate, new[] { new Enact.Core.DB.NHib.Listeners.PostUpdateEventListener() });
config.AppendListeners(NHibernate.Event.ListenerType.PostInsert, new[] { new Enact.Core.DB.NHib.Listeners.PostInsertEventListener() });
}
}
Llamar a SaveOrUpdate () o Save () hace que un objeto sea persistente. Si lo ha recuperado utilizando una ISession o desde una referencia a un objeto persistente, entonces el objeto es persistente y al vaciar la sesión se guardarán los cambios. Puede evitar este comportamiento llamando a Evict () en el objeto que lo hace transitorio.
Editado para agregar: generalmente considero que una sesión es una unidad de trabajo. Esto se implementa fácilmente en una aplicación web. usando la sesión por solicitud, pero requiere más control en WinForms.
Mi solución:
- En su creación inicial de ISession, (en algún lugar dentro de sus registros de marco de inyección) establezca DefaultReadOnly en verdadero.
- En su implementación de IRepository que rodea a NHibernate y administra la ISession y, por ejemplo, en los métodos Insertar, Actualizar, InsertUpdate y Eliminar (o similar) que llaman a ISession.Save, Update, SaveUpdate, etc. a falso
Puede configurar Session.FlushMode
como FlushMode.Never
. Esto hará que tus operaciones sean explícitas.
es decir: en tx.Commit()
o session.Flush()
. Por supuesto, esto todavía actualizará la base de datos al confirmar / vaciar. Si no desea este comportamiento, llame a session.Evict(yourObj)
y luego se convertirá en transitorio y NHibernate no emitirá ningún comando de db para ello.
Respuesta a tu edición: Sí, ese tipo te da más opciones sobre cómo controlarlo.