我刚刚发现,如果我从NHibernate会话中获取一个对象并更改对象的属性,NHibernate会在提交时自动更新对象,而不会调用Session.Update(myObj)
!
我可以看到这有什么用,但是默认行为看起来很疯狂!
更新:我现在理解持久性无知,所以这种行为现在显然是首选。我将在这里留下这个令人尴尬的问题,希望能帮助其他亵渎用户。
我怎样才能阻止这种情况发生?这是默认的NHibernate行为还是来自Fluent NHibernate的AutoPersistenceModel?
如果无法阻止这种情况,我该怎么办?除非我忽略了这一点,否则这种行为似乎会造成一个混乱。
我正在使用来自18/3/2009的NHibernate 2.0.1.4和Fluent NHibernate构建
这家伙是his answer吗?
我还读过,重写事件监听器可能是解决方案。但是,在这种情况下不会调用IDirtyCheckEventListener.OnDirtyCheck
。有谁知道我需要覆盖哪个听众?
答案 0 :(得分:13)
您可以将Session.FlushMode
设置为FlushMode.Never
。这将使您的操作明确
即:tx.Commit()
或session.Flush()
。当然,这仍然会在提交/刷新时更新数据库。如果您不想要这种行为,那么调用session.Evict(yourObj)
然后它将变为瞬态,NHibernate将不会为它发出任何db命令。
回复您的修改:是的,那家伙为您提供了更多选项来控制它。
答案 1 :(得分:3)
我的解决方案:
答案 2 :(得分:1)
调用SaveOrUpdate()或Save()会使对象持久化。如果您使用ISession或从对持久对象的引用检索它,则该对象是持久的,并且刷新会话将保存更改。您可以通过在使其成为瞬态的对象上调用Evict()来防止此行为。
编辑补充:我通常认为ISession是一个工作单元。这很容易在Web应用程序中实现。使用session-per-request但需要在WinForms中进行更多控制。
答案 3 :(得分:0)
我们通过使用带有NH的事件监听器来做到这一点(这不是我的工作 - 但我找不到我在哪里做的链接......)。
我们有一个EventListener用于读取数据,将其设置为ReadOnly - 然后一个用于Save(和SaveOrUpdate)将它们设置为已加载,因此 对象将在我们手动时保持不变打电话给Save()
。
那 - 或者你可以使用没有State / ChangeTracking的IStatelessSession。
这会在加载时立即将实体/项设置为ReadOnly。
我只包含一个Insertion事件监听器,但我的配置代码引用了所有这些监听器。
/// <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);
}
}
在保存对象时,我们将其设置为将该对象设置为Loaded(意味着它将持续存在)
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();
}
}
}
我们将它实施到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() });
}
}