我正在尝试将NHibernate与现有数据库一起使用。在数据模型中,每个表中都有列,其中包含对行进行的上次更新的时间和用户名。我如何使用NHibernate做到这一点?
我试图实现一个拦截器,它在使用IInterceptor.OnSave方法保存之前在实体中设置ChangeTime和ChangeUser。这不起作用,因为即使没有修改其他属性,设置这些属性也会触发对行的更新。
如果有任何方法告诉NHibernate排除ChangeTime和ChangeUser属性然后它进行脏检查,它可能有效。但我还没有找到任何办法来实现这一目标。
感谢您的帮助。
答案 0 :(得分:14)
您应该为预插入和预更新事件注册一个侦听器。您可以通过以下配置完成此操作:
<hibernate-configuration>
...
<event type="pre-update">
<listener class="MyListener, MyAssembly"/>
</event>
<event type="pre-insert">
<listener class="MyListener, MyAssembly"/>
</event>
</hibernate-configuration>
然后实现一个监听器 - 这样的东西(可能不完全准确 - 写下我的记忆):
public class MyListener : IPreUpdateEventListener, IPreInsertEventListener
{
public bool OnPreUpdate(PreUpdateEvent evt)
{
if (evt.Entity is IHasLastModified)
UpdateLastModified(evt.State, evt.Persister.PropertyNames);
return false;
}
public bool OnPreInsert(PreInsertEvent evt)
{
if (evt.Entity is IHasLastModified)
UpdateLastModified(evt.State, evt.Persister.PropertyNames);
return false;
}
void UpdateLastModified(object[] state, string[] names)
{
var index = Array.FindIndex(names, n => n == "LastModified");
state[index] = DateTime.Now;
}
}
并对预更新事件做同样的事情。
编辑:这个照顾插入和更新,它似乎工作。
答案 1 :(得分:5)
嘿,我只是必须在我正在进行的项目中解决这个问题,这是我的答案
public interface IDateModified
{
DateTime Created { get; set; }
DateTime Modified { get; set; }
}
public class CustomDefaultSaveOrUpdateEventListener
: DefaultSaveOrUpdateEventListener
{
protected override object EntityIsPersistent(SaveOrUpdateEvent evt)
{
var entity = evt.Entity as IDateModified;
if (entity != null)
{
entity.Modified = DateTime.Now;
}
return base.EntityIsPersistent(evt);
}
protected override object EntityIsTransient(SaveOrUpdateEvent evt)
{
var entity = evt.Entity as IDateModified;
if (entity != null)
{
entity.Created = entity.Modified = DateTime.Now;
}
return base.EntityIsTransient(evt);
}
}
然后在我的配置中(我使用Fluent NHibernate在代码中配置我的单元测试)
configuration.EventListeners.SaveOrUpdateEventListeners
= new ISaveOrUpdateEventListener[]
{
new CustomDefaultSaveOrUpdateEventListener()
};
AWESOMENESSSSSSSS!
答案 2 :(得分:1)
Mookid的回答是正确的虽然我想指出如果使用S#arp架构,NHib配置应该设置如下:
<hibernate-configuration>
<session-factory>
...
<event type="pre-update">
<listener class="MyListener, MyAssembly"/>
</event>
<event type="pre-insert">
<listener class="MyListener, MyAssembly"/>
</event>
</session-factory>
</hibernate-configuration>
事件元素进入session-factory元素。
答案 3 :(得分:0)
您也可以使用拦截器,而不是使用LIsteners: Audit changes using interceptor