【问题标题】:SQL to LINQ compare 2 entities for changes - creating an audit trailSQL to LINQ 比较 2 个实体的更改 - 创建审计跟踪
【发布时间】:2011-04-05 05:05:36
【问题描述】:

我正处于思考如何用代码做某事的假设阶段,所以我还没有具体的代码示例。但是,假设您有一个实体类型 Person(具有名字、姓氏、出生日期等属性)。当一个人去编辑一个人实体时,你可能只更新一两个字段(可能是全部,但通常不是)。将此视为实施审计跟踪(尽管不是合法的,只是提供信息),即 Tommy 于 2010 年 8 月 28 日将姓氏从 Jones 更改为 Smith。

问题是,LINQ 是否提供了一个接口来比较人员实体上从旧的、现有的与新提交的实体发生的变化?

或者必须循环遍历旧实体和新实体属性并手动对每个属性进行比较?

伪:

For each p as property in person
   If oldEntity.p <> newEntity.p then
       auditEntry = new auditEntry(oldEntity.p, newEntity.p)
   end If
Next

或者,是否有另一种/更好的方法(为部分类中的每个实体实现 IComparable 接口)可以做到这一点?

【问题讨论】:

    标签: .net linq-to-sql comparison


    【解决方案1】:

    这不正是您要寻找的,但我在此线程上发布了我用于几年前(LINQ 之前)创建的应用程序的解决方案示例:

    hint for audit log approach

    这可能会有所帮助,让您以稍微不同的方式思考解决方案。

    【讨论】:

    • 我认为这样的东西会很好用。我现在唯一不是 100% 清楚的部分是让我的字段“实现通用模板”
    【解决方案2】:

    【讨论】:

    • 这些函数告诉您哪些对象发生了变化以及这些对象的原始值是什么,但它们不会告诉您每个对象的哪些属性发生了变化。
    【解决方案3】:

    给定以下例程:

        public static void CompareProperties<T>(object source, object target)
        {
            Type type = typeof(T);
    
            CompareProperties(type, source, target);
    
            if (type.IsInterface)
            {
                Type[] baseTypes = type.GetInterfaces();
                foreach (var baseType in baseTypes)
                {
                    CompareProperties(baseType, source, target);
                }
            }
            else
            {
                type = type.BaseType;
                while (type != null)
                {
                    CompareProperties(type, source, target);
                    type = type.BaseType;
                }
            }
        }
    
        private static void CompareProperties(Type type, object source, object target)
        {
            PropertyInfo[] props = type.GetProperties(
                BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
    
            PropertyInfo[] props1 = source.GetType().GetProperties(
                BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
    
            PropertyInfo[] props2 = target.GetType().GetProperties(
                            BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
    
            foreach (PropertyInfo pi in props)
            {
                if (!pi.CanRead || !pi.CanWrite)
                    continue;
                var name = pi.Name;
                var pi1 = props1.Where(x => x.Name == name).FirstOrDefault();
                var pi2 = props2.Where(x => x.Name == name).FirstOrDefault();
                if(pi1 == null || pi2 == null)
                    continue;
    
                var expected = pi1.GetValue(source, null);
                var actual = pi2.GetValue(target, null);
    
                if(pi.PropertyType == typeof(int?))
                {
                    expected = expected ?? 0;
                    actual = actual ?? 0;
                }
                if (pi2.PropertyType.IsEnum && !pi.PropertyType.IsEnum)
                {
                    continue;
                    expected = (int)expected;
                    actual = (int)actual;
                }
                Assert.AreEqual(expected, actual, "The property '" + pi.Name + "' was not saved for the " + source.GetType().Name);
    
            }
        }
    

    您可以按如下方式比较两个对象:

    CompareProperties<CustomerProduct>(product1, productFromDb)
    

    【讨论】:

      猜你喜欢
      • 2014-12-08
      • 2011-02-17
      • 1970-01-01
      • 2012-02-27
      • 1970-01-01
      • 2018-05-15
      • 2011-01-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多