为什么`PreCollectionUpdateEvent`没有插入修改后的集合?

时间:2012-01-30 17:19:41

标签: nhibernate

在查看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;
        }
    }
}

通过调试我可以看到它被调用并正确修改我的集合。但是,出于某种原因,它首先使用AddedAtAddedBy的默认值插入我的集合中的项目,然后执行更新以填充所述值。

这是我的测试代码:

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();
}

为什么?

调试我的测试我可以看到,在我提交事务后,AddedByAddedWhen属性都已正确填充。简直不确定为什么它没有提交修改后的集合。

在我的代码中添加了一堆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继承,但同样的问题也会发生。我提交时没有将AddedAtAddedBy属性保留到数据库中。然而,我的对象将发生变化,因此下次我使用所述对象时,NHibernate将看到它是脏的并向数据库发出更新命令。我想要的是在初始提交时提交AddedAtAddedBy属性。

如果我不清楚,请告诉我。

2 个答案:

答案 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,而不仅仅是实体。