审计 NHibernate 中的多对多关系
我已经使用 IPreUpdateEventListener
和 IPreInsertEventListener
实现了监听器来审核应用程序中表的更改,并且除了我的多对多关系中没有附加数据之外,一切正常。连接表(即我没有用于连接表的 POCO)。
每个可审核对象都实现一个 IAuditable 接口,因此事件侦听器会检查 POCO 是否属于 IAuditable 类型,如果是,则记录对该对象的任何更改。查找表实现了一个IAuditableProperty
接口,因此如果IAuditable
POCO的属性指向查找表,则更改将记录在主POCO的日志中。
所以,问题是,我应该如何确定我正在使用多对多集合并将更改记录在我的审核表中?
编辑:我正在使用 NHibernate 2.1.2.4000
//first two checks for LastUpdated and LastUpdatedBy ommitted for brevity
else if (newState[i] is IAuditable)
{
//Do nothing, these will record themselves separately
}
else if (!(newState[i] is IAuditableProperty) && (newState[i] is IList<object> || newState[i] is ISet))
{
//Do nothing, this is a collection and individual items will update themselves if they are auditable
//I believe this is where my many-to-many values are being lost
}
else if (!isUpdateEvent || !Equals(oldState[i], newState[i]))//Record only modified fields when updating
{
changes.Append(preDatabaseEvent.Persister.PropertyNames[i])
.Append(": ");
if (newState[i] is IAuditableProperty)
{
//Record changes to values in lookup tables
if (isUpdateEvent)
{
changes.Append(((IAuditableProperty)oldState[i]).AuditPropertyValue)
.Append(" => ");
}
changes.Append(((IAuditableProperty)newState[i]).AuditPropertyValue);
}
else
{
//Record changes for primitive values
if(isUpdateEvent)
{
changes.Append(oldState[i])
.Append(" => ");
}
changes.Append(newState[i]);
}
changes.AppendLine();
}
I have implemented listeners to audit changes to tables in my application using IPreUpdateEventListener
and IPreInsertEventListener
and everything works except for my many-to-many relationships that don't have additional data in the joining table (i.e. I don't have a POCO for the joining table).
Each auditable object implements an IAuditable
interface, so the event listener checks to see if a POCO is of type IAuditable
, and if it is it records any changes to the object. Look up tables implement an IAuditableProperty
inteface, so if a property of the IAuditable
POCO is pointing to a lookup table, the changes are recorded in the log for the main POCO.
So, the question is, how should I determine I'm working with a many-to-many collection and record the changes in my audit table?
Edit: I'm using NHibernate 2.1.2.4000
//first two checks for LastUpdated and LastUpdatedBy ommitted for brevity
else if (newState[i] is IAuditable)
{
//Do nothing, these will record themselves separately
}
else if (!(newState[i] is IAuditableProperty) && (newState[i] is IList<object> || newState[i] is ISet))
{
//Do nothing, this is a collection and individual items will update themselves if they are auditable
//I believe this is where my many-to-many values are being lost
}
else if (!isUpdateEvent || !Equals(oldState[i], newState[i]))//Record only modified fields when updating
{
changes.Append(preDatabaseEvent.Persister.PropertyNames[i])
.Append(": ");
if (newState[i] is IAuditableProperty)
{
//Record changes to values in lookup tables
if (isUpdateEvent)
{
changes.Append(((IAuditableProperty)oldState[i]).AuditPropertyValue)
.Append(" => ");
}
changes.Append(((IAuditableProperty)newState[i]).AuditPropertyValue);
}
else
{
//Record changes for primitive values
if(isUpdateEvent)
{
changes.Append(oldState[i])
.Append(" => ");
}
changes.Append(newState[i]);
}
changes.AppendLine();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这不会触发的原因是因为集合没有更改,即它们仍然是之前的 ICollection 实例,但是集合的内容已更改。
我自己也找过这个,事件监听器不处理这种情况。这可能已在 v3.0 中修复(但不要引用我的话)。有一些不理想的解决方法:
1)在对象上放置一个属性,该属性可以出于审计目的生成集合的字符串表示形式。
2)使集合中的项目实现接口,以便对它们进行单独审核。
编辑:还有第三个选项:
“而不是多对多,我有一个多对一的连接表,然后一对多从它进入属性表。我隐藏连接表 POCO 背后有多对多连接每一端的逻辑,但仍然必须实现该对象及其上的所有接口。”
The reason that this won't fire is because the collections haven't changed, i.e. they're still the same instance of ICollection that was there before, however the content of the collections have changed.
I've looked for this myself, and the event listeners do not handle this situation. This may have been fixed for v3.0 (but don't quote me on that). There are a couple of non ideal workarounds:
1)Put a property on the object which makes a string representation of the collection for the purposes of auditing.
2)Make the items in the collection implement the interface so they are audited individually.
Edit: There is a third option:
"Rather than a many-to-many, I have a many-to-one going to the joining table, and then a one-to-many coming from it into the property table. I hide the joining table POCO behind the logic of each of the ends of the many-to-many joins, but still have to implement the object and all the interfaces on it."
事实证明,实际上有一种方法可以通过事件侦听器来执行此操作,而无需公开连接表。您只需使事件侦听器实现 IPostCollectionRecreateEventListener 或 IPreCollectionRecreateEventListener 即可。根据我的测试,只要刷新会话,这些事件就会因更改的集合而被触发。这是我的 PostRecreateCollection 方法的事件侦听器代码。
最棘手的部分是获取正在更新的集合的名称。您必须通过 PersistenceContext 串联起来才能获取集合的 Persister,这使您可以访问它的元数据。
因为这些事件或监听器都没有被记录下来,所以我不知道除了刷新之外,这个事件是否会在其他情况下抛出,所以它有可能创建错误的审计条目。我计划在该领域做一些进一步的研究。
It turns out that there actually is a way to do this via Event Listeners without having to expose the joining tables. You just have to make your event listener implement IPostCollectionRecreateEventListener or IPreCollectionRecreateEventListener. Based on my testing these events get fired for changed collections whenever the session is flushed. Here's my event listener code for the PostRecreateCollection method.
The most tricky part is getting the name of the collection being updated. You have to chain your way through the PersistenceContext to get the Persister for the collection which gives you access to it's meta data.
Because none of these events or listeners are documented I don't know if this event gets thrown in other situations besides flush, so there's a potential it could create false audit entries. I plan to do some further research in that area.