NHibernate更改审计和组件

3
我们的系统架构的一个重要组成部分是必须为用户提供仪表板,以便他们能够明确地将数据更改从一个环境发布到另一个环境。我们研究了NH Evers,但我们需要将许多特定于领域的内容融入到架构中。我们一直在成功地使用NHibernate的事件模型来跟踪和记录系统中的状态更改(到另一个表),但最近在组件方面遇到了问题。当IPostInsertEventListener和IPostUpdateEventListener被触发时,它会发布表示实体当前状态的值数组。在更新的情况下,它还会发布表示先前状态的数组。我们正在使用这些数组将“之前”和“之后”的状态保存到我们的表格中。当属性是一个组件时,实际值(区域中的项目)是组件实例本身 - 即一个未打包的复杂对象。除了交叉引用元模型映射器并反射出该映射器以提取各个值之外,我如何获取组件的实际值?我能够访问映射到组件成员的列名,但无法访问之前和之后的值。
我一直在搜索NH源代码,但没有找到如何提取这些值的方法。显然,NH知道如何在内部执行此操作,因为它能够正确地发布SQL。这是我目前拥有的代码的修改/详细版本,突出了问题:
        public static RowChangedReport Load(IChangeTrackable trackable, object entityId, AbstractEntityPersister persister, object[] state, object[] oldState)
    {
        var report = new RowChangedReport
            {
                Entity = trackable,
                EntityTypeFullName = persister.EntityName,
                TableName = new TableName(persister.GetTableName()),
                EntityId = entityId,
            };

        var authContext = AuthenticationContext.Current;

        if (authContext != null)
            report.SecurityContextUserId = authContext.UserId;

        if (persister.PropertyNames != null && state != null)
        {
            report.ChangedType = oldState == null ? RowChangedTypes.New : RowChangedTypes.Modified;

            for (var index = 0; index < persister.PropertyNames.Length; index++)
            {
                var propertyName = persister.PropertyNames[index];

                IType propertyType = persister.PropertyTypes[index];

                if (!propertyType.IsCollectionType)
                {
                    AddColumnChangeReport(persister, state, oldState, index, propertyName, report);
                }
            }
        }

        report.FinalizeState();

        return report;
    }

    private static void AddColumnChangeReport(AbstractEntityPersister persister, object[] state, object[] oldState, int index, string propertyName, RowChangedReport report)
    {
        var currentValue = state[index];

        // for simple properties, this is always a single element array
        // for components, this is an array with an element for each member on the component - i.e. how the component is mapped
        string[] columns = persister.GetPropertyColumnNames(propertyName);

        var previousValue = oldState == null ? null : oldState[index];

        if (!Equals(currentValue, previousValue))
        {
            if (report.ChangedType == RowChangedTypes.Modified && propertyName == IsActivePropertyName)
                report.FlagAsDeleted();

            foreach (var column in columns)
            {
                // if this is a component, both the currentValue and the previousValue are complex objects
                // need to have a way to get the actual member value per column!
                report.AddChange(new ColumnChangedReport(report, propertyName, column, previousValue, currentValue));
            }
        }
    }

提供了上面的编辑解决方案 - kellyb
1个回答

2

好的,经过几个小时阅读NH代码,我偶然发现了Tuplizer并追溯到属性Type。所以解决方案很简单 - 对于组件,您需要将它们检测为这样的组件,转换为ComponentType类型,然后询问ComponentType属性值。这是一些对我有效的代码:

        public static RowChangedReport Load(IChangeTrackable trackable, object entityId, AbstractEntityPersister persister, object[] state, object[] oldState)
    {
        var report = new RowChangedReport
            {
                Entity = trackable,
                EntityTypeFullName = persister.EntityName,
                TableName = new TableName(persister.GetTableName()),
                EntityId = entityId,
            };

        var authContext = AuthenticationContext.Current;

        if (authContext != null)
            report.SecurityContextUserId = authContext.UserId;

        if (persister.PropertyNames != null && state != null)
        {
            report.ChangedType = oldState == null ? RowChangedTypes.New : RowChangedTypes.Modified;

            for (var index = 0; index < persister.PropertyNames.Length; index++)
            {
                var propertyName = persister.PropertyNames[index];

                IType propertyType = persister.PropertyTypes[index];

                if (!propertyType.IsCollectionType)
                {
                    AddColumnChangeReport(persister, state, oldState, index, propertyName, propertyType, report);
                }
            }
        }

        report.FinalizeState();

        return report;
    }

    private static void AddColumnChangeReport(AbstractEntityPersister persister, object[] state, object[] oldState, int index, string propertyName, IType propertyType, RowChangedReport report)
    {
        var currentValue = state[index];

        string[] columns = persister.GetPropertyColumnNames(propertyName);

        var previousValue = oldState == null ? null : oldState[index];

        if (!Equals(currentValue, previousValue))
        {
            if (report.ChangedType == RowChangedTypes.Modified && propertyName == IsActivePropertyName)
                report.FlagAsDeleted();

            if (propertyType.IsComponentType)
            {
                ComponentType component = (ComponentType)propertyType;

                object[] componentCurrentValues = null;

                if (currentValue != null)
                    componentCurrentValues = component.GetPropertyValues(currentValue, EntityMode.Poco);

                object[] componentPreviousValues = null;

                if (currentValue != null)
                    componentPreviousValues = component.GetPropertyValues(previousValue, EntityMode.Poco);

                if ((componentCurrentValues != null && componentCurrentValues.Length != columns.Length) ||
                    (componentPreviousValues != null && componentPreviousValues.Length != columns.Length))
                    throw new ConventionViolationException(GetComponentArraysExceptionMessage(persister, propertyName, columns, componentPreviousValues, componentCurrentValues));

                for (int i = 0; i < columns.Length; i++)
                {
                    var column = columns[i];
                    var componentPreviousValue = componentPreviousValues == null ? null : componentPreviousValues[i];
                    var componentCurrnetValue = componentCurrentValues == null ? null : componentCurrentValues[i];

                    report.AddChange(new ColumnChangedReport(report, propertyName, column, componentPreviousValue, componentCurrnetValue));
                }
            }
            else
            {
                if (columns.Length > 1)
                    throw new ConventionViolationException("Expected only component properties to have multiple columns.  Property '{0}' on entity {1} is violating that assumption.".FormatWith(propertyName, persister.EntityName));

                report.AddChange(new ColumnChangedReport(report, propertyName, columns[0], previousValue, currentValue));
            }
        }
    }

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