在查看NHibernate.Envers
代码之后,我意识到我正在实现错误的界面。现在我知道使用什么接口的东西工作得更好了。
我目前的实现如下:
public class PreCollectionUpdate : IPreCollectionUpdateEventListener
{
public void OnPreUpdateCollection(PreCollectionUpdateEvent @event)
{
var collectionEntry = @event.Session.PersistenceContext.GetCollectionEntry(@event.Collection);
if(!collectionEntry.LoadedPersister.IsInverse)
return;
var collection = @event.Collection;
var collectionEntries = collection.Entries(collectionEntry.LoadedPersister);
foreach(var entry in collectionEntries)
{
if(!(entry is TrackableEntity))
return;
var trackableEntity = entry as TrackableEntity;
trackableEntity.AddedAt = Time.Now;
trackableEntity.AddedBy = User.Current;
}
}
}
通过调试我可以看到它被调用并正确修改我的集合。但是,出于某种原因,它首先使用AddedAt
和AddedBy
的默认值插入我的集合中的项目,然后执行更新以填充所述值。
这是我的测试代码:
using (var transaction = Session.BeginTransaction())
{
var locate = new Locate
{
TicketNumber = 123456789,
Status = Status.InProgress
};
Session.Save(locate);
transaction.Commit();
}
using (var transaction = Session.BeginTransaction())
{
var locate1 = Session.Get<Locate>(1);
locate1.AddReview(new AllClear());
Session.Save(locate1);
transaction.Commit();
}
using (var transaction = Session.BeginTransaction())
{
var locate1 = Session.Load<Locate>(1);
transaction.Commit();
}
为什么?
调试我的测试我可以看到,在我提交事务后,AddedBy
和AddedWhen
属性都已正确填充。简直不确定为什么它没有提交修改后的集合。
在我的代码中添加了一堆Console.Write
语句我可以看到我的事件监听器在提交会话后被称为。
NHibernate: INSERT INTO Locates (AddedAt, AddedBy, TicketNumber, Status, SomeOtherField) VALUES (@p0, @p1, @p2, @p3, @p4); select last_insert_rowid();@p0 = 1/1/0001 00:00:00 [Type: DateTime (0)], @p1 = NULL [Type: String (0)], @p2 = 123456789 [Type: Int64 (0)], @p3 = 'InProgress' [Type: String (0)], @p4 = NULL [Type: String (0)]
Saving review...
Commiting...
NHibernate: INSERT INTO "Review" (AddedAt, AddedBy, Locate_id) VALUES (@p0, @p1, @p2); select last_insert_rowid();@p0 = 1/1/0001 00:00:00 [Type: DateTime (0)], @p1 = NULL [Type: String (0)], @p2 = NULL [Type: Int32 (0)]
In event listener...
Completed filling auditable properties.
我也试过从IFlushEntityEventListener
继承,但同样的问题也会发生。我提交时没有将AddedAt
和AddedBy
属性保留到数据库中。然而,我的对象将发生变化,因此下次我使用所述对象时,NHibernate将看到它是脏的并向数据库发出更新命令。我想要的是在初始提交时提交AddedAt
和AddedBy
属性。
如果我不清楚,请告诉我。
答案 0 :(得分:2)
我不相信你可以使用PreUpdateCollectionEventListener来做你想做的事情。 PreUpdateEventListeners都在nhibernate pipline中运行得很晚因此,在抛出事件的时候,NHibernate已经将实体的状态分解为内存。您需要更改状态和实体本身,但是在PreUpdateCollectionEvent中,您无权访问状态,据我所知,我总是按照常规的PreUpdateEventListener完成您要做的事情,例如这样的事情应该工作:
public class AuditEventListener : IPreUpdateEventListener
{
public bool OnPreUpdate(PreUpdateEvent @event)
{
// Grab the entity from the event
var trackableEntity = @event.Entity as TrackableEntity;
if ( trackableEntity == null)
return false;
// Set the state for the entity (needed to write new values to the db)
Set(@event.Persister, @event.State, "AddedAt", time);
Set(@event.Persister, @event.State, "AddedByBy", name);
// Set the entity values (needed to keep your session in sync)
trackableEntity.AddedAt = Time.Now;
trackableEntity.AddedBy = User.Current;
return false;
}
private void Set(IEntityPersister persister, object[] state, string propertyName, object value)
{
var index = Array.IndexOf(persister.PropertyNames, propertyName);
if (index == -1)
return;
state[index] = value
}
PS。我知道我曾经读过Ayende关于此的一篇非常好的帖子,但我现在找不到它。
答案 1 :(得分:1)
我的猜测是你需要modify the state as well,而不仅仅是实体。