Ayende有一篇关于如何使用事件处理程序为NHibernate(这里)实现简单审计跟踪的文章.
不幸的是,正如在注释中可以看到的那样,他的实现导致抛出以下异常:集合xxx未由flush()处理
问题似乎是在脏属性上对ToString的隐式调用,如果dirty属性也是映射实体,则会导致麻烦.
我尽最大努力建立一个有效的实施但没有运气.
有谁知道一个有效的解决方案?
小智 9
我能够使用以下解决方法解决相同的问题:在侦听器中的当前持久性上下文中的所有集合上将processed标记设置为true
public void OnPostUpdate(PostUpdateEvent postEvent)
{
if (IsAuditable(postEvent.Entity))
{
//skip application specific code
foreach (var collection in postEvent.Session.PersistenceContext.CollectionEntries.Values)
{
var collectionEntry = collection as CollectionEntry;
collectionEntry.IsProcessed = true;
}
//var session = postEvent.Session.GetSession(EntityMode.Poco);
//session.Save(auditTrailEntry);
//session.Flush();
}
}
Run Code Online (Sandbox Code Playgroud)
希望这可以帮助.
修复应该如下.创建一个新的事件侦听器类,并从NHibernate.Event.Default.DefaultFlushEventListener派生它:
[Serializable]
public class FixedDefaultFlushEventListener: DefaultFlushEventListener
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
protected override void PerformExecutions(IEventSource session)
{
if (log.IsDebugEnabled)
{
log.Debug("executing flush");
}
try
{
session.ConnectionManager.FlushBeginning();
session.PersistenceContext.Flushing = true;
session.ActionQueue.PrepareActions();
session.ActionQueue.ExecuteActions();
}
catch (HibernateException exception)
{
if (log.IsErrorEnabled)
{
log.Error("Could not synchronize database state with session", exception);
}
throw;
}
finally
{
session.PersistenceContext.Flushing = false;
session.ConnectionManager.FlushEnding();
}
}
}
Run Code Online (Sandbox Code Playgroud)
在NHibernate configuraiton中注册它:
cfg.EventListeners.FlushEventListeners = new IFlushEventListener[] { new FixedDefaultFlushEventListener() };
Run Code Online (Sandbox Code Playgroud)
您可以在Hibernate JIRA中阅读有关此错误的更多信息:https: //hibernate.onjira.com/browse/HHH-2763
NHibernate的下一个版本应该包含该修复.
这一点都不容易。我写了这样的东西,但它非常适合我们的需求,而且不是微不足道的。
一些额外的提示:
您可以使用以下命令测试引用是否已加载
NHibernateUtil.IsInitialized(entity)
Run Code Online (Sandbox Code Playgroud)
或者
NHibernateUtil.IsPropertyInitialized(entity, propertyName)
Run Code Online (Sandbox Code Playgroud)
您可以将集合投射到IPersistentCollection. 我实现了一个IInterceptor获取每个属性的 NHibernate 类型的位置,我不知道在使用事件时可以在哪里获取它:
if (nhtype.IsCollectionType)
{
var collection = previousValue as NHibernate.Collection.IPersistentCollection;
if (collection != null)
{
// just skip uninitialized collections
if (!collection.WasInitialized)
{
// skip
}
else
{
// read collections previous values
previousValue = collection.StoredSnapshot;
}
}
}
Run Code Online (Sandbox Code Playgroud)
当您从 NHibernate 获取更新事件时,实例就会被初始化。您可以安全地访问基本类型的属性。当您想要使用 时ToString,请确保您的ToString实现不会访问任何引用的实体或任何集合。
您可以使用 NHibernate 元数据来确定类型是否映射为实体。这对于在对象模型中导航可能很有用。当您引用另一个实体时,当它发生更改时,您将收到有关该实体的其他更新事件。
| 归档时间: |
|
| 查看次数: |
4340 次 |
| 最近记录: |