如何关闭NHibernate';s自动(脏检查)更新行为?

如何关闭NHibernate';s自动(脏检查)更新行为?,nhibernate,Nhibernate,我刚刚发现,如果我从NHibernate会话中获取一个对象并更改该对象的属性,NHibernate将在提交时自动更新该对象,而无需调用会话。更新(myObj) 我可以看出这是多么有用,但作为默认行为,它似乎疯狂 更新:我现在理解了持久性无知,因此这种行为现在显然是首选。我将把这个现在令人尴尬的问题留在这里,希望能帮助其他亵渎者 我怎样才能阻止这种事情发生?这是默认的NHibernate行为还是来自Fluent NHibernate的AutoPersistenceModel 如果没有办法阻止,我该

我刚刚发现,如果我从NHibernate会话中获取一个对象并更改该对象的属性,NHibernate将在提交时自动更新该对象,而无需调用
会话。更新(myObj)

我可以看出这是多么有用,但作为默认行为,它似乎疯狂

更新:我现在理解了持久性无知,因此这种行为现在显然是首选。我将把这个现在令人尴尬的问题留在这里,希望能帮助其他亵渎者

我怎样才能阻止这种事情发生?这是默认的NHibernate行为还是来自Fluent NHibernate的AutoPersistenceModel

如果没有办法阻止,我该怎么办?除非我没有抓住要点,否则这种行为似乎会造成一种混乱

我正在使用NHibernate 2.0.1.4和2009年3月18日的流畅NHibernate构建

这家伙对吗


我还读过,重写事件侦听器可能是解决这个问题的一个方法。但是,在这种情况下,不会调用IDirtyCheckEventListener.OnDirtyCheck。有人知道我需要覆盖哪个侦听器吗?

您可以将
会话.FlushMode
设置为
FlushMode.Never
。这将使您的操作更加明确

ie:on
tx.Commit()
session.Flush()
。当然,这仍然会在提交/刷新时更新数据库。如果您不希望出现这种行为,那么调用
session.execute(yourObj)
,它将变为瞬态,NHibernate将不会为其发出任何db命令

对编辑的响应:是的,那个家伙给了你更多控制它的选项。

调用SaveOrUpdate()或Save()会使对象持久化。如果您使用ISession或从对持久对象的引用检索到它,那么该对象是持久的,刷新会话将保存更改。您可以通过对对象调用execute()来防止这种行为,从而使其成为瞬态对象

编辑补充:我一般认为一个单位是一个工作单位。这很容易在web应用程序中实现。使用每个请求的会话,但在WinForms中需要更多控制。

我的解决方案:

  • 在初始ISession创建过程中,(在注入框架注册的某处)将DefaultReadOnly设置为true
  • 在围绕NHibernate并管理ISession的IRepository实现中,以及在调用ISession.Save、Update、SaveUpdate等的Insert、Update、INSERTUDATE和Delete(或类似)方法中,为实体调用SetReadOnly,并将标志设置为false

  • 我们通过在NH中使用事件监听器实现了这一点(这不是我的工作-但我找不到我在哪里做的链接…)

    我们有一个EventListener,用于在读取数据时将其设置为只读,然后有一个用于Save(和SaveOrUpdate)将其设置为已加载,这样当我们手动调用对象上的
    Save()
    时,该对象将保持不变

    或者您可以使用没有状态/变更跟踪的IStatelessSession

    这将在加载时立即将实体/项设置为只读

    我只包含了一个插入事件侦听器,但我的配置代码引用了所有这些侦听器

    //
    ///加载对象后,侦听器会将其状态更改为只读,以便
    ///NH不会自动保存它
    /// 
    /// 
    ///要保存此对象,将使用SaveUpdateEventListener。
    /// 
    公共类PostLoadEventListener:IPostLoadEventListener
    {
    PostLoad上的公共无效(PostLoadEvent@event)
    {
    EntityEntry=@event.Session.PersistenceContext.GetEntry(@event.Entity);
    entry.BackSetStatus(Status.ReadOnly);
    }
    }
    
    保存对象时,我们调用此函数将该对象设置为已加载(这意味着它现在将保持不变)

    公共类SaveUpdateEventListener:ISaveOrUpdateEventListener
    {
    public static readonly CascadingAction ResetReadOnly=new ResetReadOnlyCascadeAction();
    /// 
    ///将任何已加载项的状态更改为只读。
    /// 
    /// 
    ///更改所有已加载实体的状态,以便NH不再跟踪这些实体上的更改。
    /// 
    SaveOrUpdate(SaveOrUpdateEvent@event)上的公共无效
    {
    var session=@event.session;
    EntityEntry=session.PersistenceContext.GetEntry(@event.Entity);
    if(entry!=null&&entry.Persister.IsMutable&&entry.Status==Status.ReadOnly)
    {
    条目.返回状态(状态.已加载);
    cascadeoUpdate(@event,entry.Persister,@event.entry);
    }
    }
    私有静态void cascadeUpdate(SaveOrUpdateEvent@event,ientTypersister EntityPerister,
    对象实体(entityEntry)
    {
    IEventSource=@event.Session;
    source.PersistenceContext.IncrementCascadeLevel();
    尝试
    {
    新的级联(ResetReadOnly,CascadePoint.BeforeFlush,source).CascadeOn(entityPersister,entityEntry);
    }
    最后
    {
    source.PersistenceContext.DecrementScadelevel();
    }
    }
    }
    
    我们将其实施到NH中,因此:

        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() });
            }
        }
    
    公共静态ISessionFactory CreateSessionFactory(IPersistenceConfiger数据库配置、动作映射配置、bool启用的变更跟踪、bool启用的数据编辑、int queryTimeout)
    {
    流畅地返回。Configure()
    .Database(dbConfig)
    .Mappings(mappingConfig)
    .Mappings(x=>x.FluentMappings.AddFromAssemblyOf())
    .ExposeConfiguration(x=>Configure(x,enabledChangeTracking,enabledAuditing,queryTimeout))
    .BuildSessionFactory();
    }
    /// 
    ///配置指定的配置。
    /// 
    ///配置。
    ///如果设置为true[启用更改跟踪]。
    ///查询超时(分钟)。
    私有静态无效配置(NHibernate.Cfg.Configuration config,bool enableChangeTracking,bool ena
    
    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();
            }
        }
    }
    
        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() });
            }
        }