NHibernate更新时的事件审计

5
以下代码在插入时可以正常工作,但在更新时modifier从未被设置,有任何想法吗?
预更新代码正在运行,并正确地将状态和实体值设置为所需的值。然而,在查看生成的SQL时,nhibernate没有将该字段包含在更新查询中。
/// <summary> Updates auditable objects </summary>
public class AuditEventListener : IPreInsertEventListener, IPreUpdateEventListener
{
    private ISecurityManager securityManager;

    public bool OnPreInsert( PreInsertEvent args )
    {
        var auditable = args.Entity as IAuditable;
        if (auditable != null) {

            Set( x => auditable.Creator, args.Persister, auditable, args.State, SecurityManager.Identity );
            Set( x => auditable.DateAdded, args.Persister, auditable, args.State, Clock.Now );
        }
        return false;
    }

    public bool OnPreUpdate( PreUpdateEvent args )
    {
        var auditable = args.Entity as IAuditable;
        if (auditable != null) {

            Set( x => auditable.Modifier, args.Persister, auditable, args.State, SecurityManager.Identity );
            //Set( x => auditable.DateModified, args.Persister, auditable, args.State, Clock.Now );
        }
        return false;
    }


    /// <summary> Type safe method to update sate and entity </summary>
    private void Set<T, U>( Expression<Func<U, T>> expression, IEntityPersister persister, U instance, object[] state, T value )
    {
        var member = expression.Body as MemberExpression;
        if (member != null) {

            var index = Array.IndexOf( persister.PropertyNames, member.Member.Name );
            if (index == -1) {
                return;
            }
            state[index] = value;

            var property = (member.Member as PropertyInfo);
            if (property != null) {
                property.SetValue( instance, value, null );
            }
        }
    }

    ISecurityManager SecurityManager
    {
        get { /* From IoC */ }
    }

}

这段代码看起来很好,尽管Set方法有些不寻常。如果你在OnPreUpdate上设置一个断点,当你持久化一个更新后的对象时它会被调用吗? - Jamie Ide
是的,我认为问题与该属性未被nhibernate视为脏数据有关。 - Daniel Little
2个回答

3

编辑1:此答案已经得到改进。
编辑2:看起来问题的真正原因是将dynamic-update设置为true,如此处所述,但这个解决方案仍然适用于我。

当你在OnFlushDirty函数中更新它们时,更改会被保存,该函数会较早地调用。

public override bool OnFlushDirty( object entity, object id, object[] currentState, object[] previousState, string[] propertyNames, NHibernate.Type.IType[] types )
{
    bool result = false;

    if (entity is IAuditable) {
        var auditable = (IAuditable)entity;

        Set( x => auditable.Modifier, propertyNames, auditable, currentState, SecurityManager.Identity );
        //Set( x => auditable.DateModified, args.Persister, auditable, args.State, TwentyClock.Now );

        result = true;
    }

    return result;
}

@Max Schilling 对不起,这个答案更好吗? - Daniel Little

0
对我们来说,原因是 NHibernate 使用相同的列名连接表;因此,我们更新了该列名的第一个实例,但没有更新后续实例。我们这样做:
    protected void Set(IEntityPersister persister, object[] state, string propertyName, object value)
    {
        var index = Array.IndexOf(persister.PropertyNames, propertyName);
        while (index > -1)
        {
            state[index] = value;
            index = Array.IndexOf(persister.PropertyNames, propertyName, index + 1);
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接