使用更新事件进行休眠审计

Posted

技术标签:

【中文标题】使用更新事件进行休眠审计【英文标题】:nhibernate auditing with events on update 【发布时间】:2011-03-11 00:42:28 【问题描述】:

以下代码在插入时有效,但在更新时 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 上设置断点,当你持久化一个更新的对象时它会被调用吗? 是的,我认为问题与该属性不被 nhibernate 视为脏有关。 【参考方案1】:

编辑 1:此答案已改进 编辑 2:看来问题的真正原因是 dynamic-update 设置为 true 为 found here 但是这个解决方案仍然适用于我。

当您在之前调用的 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 抱歉,这个答案更好吗?【参考方案2】:

对我们来说,这是因为 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);
        
    

【讨论】:

以上是关于使用更新事件进行休眠审计的主要内容,如果未能解决你的问题,请参考以下文章

如何使用休眠环境避免不必要的审计

使用 EntityManager 进行休眠更新

AbstractMongoEventListener 识别更新或添加事件 spring boot mongoDb

休眠中的并发更新处理

在 where 子句中提取/更新休眠字符串参数值

使用 Hibernate Envers 进行审计