我在NHibernate 2.1中配置了一个PreInsert和PreDelete事件监听器。对于特定表上的插入和删除,我想将审计事件写入单独的审计表。
public class AuditEventListener : IPreInsertEventListener, IPreDeleteEventListener
{
private static readonly ILog Log = LogManager.GetLogger(typeof(AuditEventListener));
public bool OnPreInsert(PreInsertEvent @event)
{
if (!(@event.Entity is IAuditable))
return false;
return AuditEvent(@event.Session.GetSession(EntityMode.Poco),
true, (@event.Entity as IAuditable));
}
public bool OnPreDelete(PreDeleteEvent @event)
{
if (!(@event.Entity is IAuditable))
return false;
return AuditEvent(@event.Session.GetSession(EntityMode.Poco),
false, (@event.Entity as IAuditable));
}
private bool AuditEvent(ISession session, bool isInsert, IAuditable entity)
{
if (entity is ArticleBinding)
{
if (Log.IsDebugEnabled)
Log.DebugFormat(" audit event ({0}), entity is ArticleBinding", ((isInsert) ? "Insert" : "Delete"));
AddArticleBindingAuditEvent(session, isInsert,
(entity as ArticleTagBinding));
}
return false;
}
private void AddArticleBindingAuditEvent(ISession session,
bool isInsert, ArticleBinding binding)
{
var auditRecord = new AuditArticleBinding()
{
ArticleId = binding.ArticleId,
Action = (isInsert) ? "Add" : "Delete",
LoggedBy = string.IsNullOrEmpty(Thread.CurrentPrincipal.Identity.Name)
? "Unknown"
: Thread.CurrentPrincipal.Identity.Name
};
session.Save(auditRecord);
}
}
我解决了使用相同会话的问题,这导致了异常。现在,所有代码都运行正常,我的日志语句被命中,但审计记录永远不会被插入。使用NHProf,我可以看到INSERT调用永远不会发生。
为什么上面的代码不能导致INSERT?
答案 0 :(得分:4)
我目前正在研究完全相同的事情并遇到了同样的问题。尝试保存新实体并且甚至没有执行INSERT
语句。我发现了一篇关于using Pre[Update|Insert]Listeners to audit per record的文章,其中一条评论询问是否插入了一个新实体,而作者则回复说需要一个子会话。
private void AddArticleBindingAuditEvent(ISession session,
bool isInsert, ArticleBinding binding)
{
var childSession = e.Session.GetSession(EntityMode.Poco);
var auditRecord = new AuditArticleBinding()
{
ArticleId = binding.ArticleId,
Action = (isInsert) ? "Add" : "Delete",
LoggedBy = string.IsNullOrEmpty(Thread.CurrentPrincipal.Identity.Name)
? "Unknown"
: Thread.CurrentPrincipal.Identity.Name
};
childSession.Save(auditRecord);
childSession.Flush();
}
您的另一个参考(我今天发现)是Auditing with NHibernate Listeners。它给出了一个关于插入新审计日志但是使用Post侦听器的完整示例,并且是非实体特定的(与使用persister执行与查找已更改值的操作几乎相同)。我不确定这对于使用Pre听众有什么好处。
作为“只是在案例中”,您需要确保将事件监听器挂钩到您的配置:
var eventListener = new AuditEventListener();
config.SetListener(ListenerType.PreInsert, eventListener);
config.SetListener(ListenerType.PreDelete, eventListener);
完全披露:我对NHibernate很陌生,所以如果有什么我错过或可以做得更好,请告诉我。上面的方法适用于我,因为我的记录已成功插入到数据库中,但在某些情况下它确实失败了。虽然我几乎可以肯定这是我的应用程序特有的(我是代码库的新手,所以还在处理)
答案 1 :(得分:0)
在花了一整天的时间试图找出问题的根本原因而没有成功之后,我希望找到这个thread来解释:
看看Hibernate代码,它看起来像插入的是什么 仅使用PreInsertEvent的“state”属性。即便如此 你更新event.getEntity(),我不认为它得到 在插入阶段插入。
解决方案包括:1)更新实体以传递验证(如@NotNull)和2)更新状态以使新值保持在数据库中!
在我的应用程序中,这会生成一个丑陋的代码,如:
@Override
public boolean onPreInsert(PreInsertEvent event) {
Object entity = event.getEntity();
// Assumption: entity cannot be null
if (entity instanceof AbstractBase) {
String[] names = event.getPersister().getPropertyNames();
for (int i = 0; i < names.length; ++i) {
if ("insertWhen".equals(names[i])) {
((AbstractBase<?>) entity).setInsertWhen(new Date());
event.getState()[i] = ((AbstractBase<?>) entity).getInsertWhen();
}
else if (...) {
...
}
}
}
我很惊讶地看到6年前记录的这个问题对我们许多人来说仍然是一个问题。
我希望这会有所帮助。