天天看点

c# .net core 属性跟踪的几种方式

Mark:jiaguoxinzhi Linyee 属性跟踪 

首先声明,,此篇文章内容还处于研究阶段,不确保,内容正确性。。

1、Ef core方式 Microsoft.EntityFrameworkCore 3.0.0

EF core源码翻来覆去N多次,,始终没有明白具体是怎么监控属性变更的。。

大致上是,一个实体类分,跟踪映射类、原始类。

主要是通过使用 ValueComparer 来判断是否已更新

db.SaveChanges()时

TryDetectChanges();//状态跟踪

var entitiesSaved = DbContextDependencies.StateManager.SaveChanges(acceptAllChangesOnSuccess);//保存

 return entitiesSaved;

可见实际的保存动作是在SaveChanges(acceptAllChangesOnSuccess)

var entriesToSave = GetEntriesToSave();

var result = SaveChanges(entriesToSave);

    public abstract partial class InternalEntityEntry : IUpdateEntry

 SetPropertyModified SetEntityState 会增加 ChangedCount;

/// <summary>
        ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
        ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
        ///     any release. You should only use it directly in your code with extreme caution and knowing that
        ///     doing so can result in application failures when updating to a new Entity Framework Core release.
        /// </summary>
        public virtual void DetectChanges(IStateManager stateManager)
        {
            _logger.DetectChangesStarting(stateManager.Context);

            foreach (var entry in stateManager.ToList()) // Might be too big, but usually _all_ entities are using Snapshot tracking

            {
                if (entry.EntityType.GetChangeTrackingStrategy() == ChangeTrackingStrategy.Snapshot
                    && entry.EntityState != EntityState.Detached)
                {
                    LocalDetectChanges(entry);
                }
            }

            _logger.DetectChangesCompleted(stateManager.Context);
        }
           
private void LocalDetectChanges(InternalEntityEntry entry)
        {
            var entityType = entry.EntityType;

            foreach (var property in entityType.GetProperties())
            {
                if (property.GetOriginalValueIndex() >= 0
                    && !entry.IsModified(property)
                    && !entry.IsConceptualNull(property))
                {
                    var current = entry[property];
                    var original = entry.GetOriginalValue(property);

                    var comparer = property.GetValueComparer() ?? property.FindMapping()?.Comparer;

                    if (comparer == null)
                    {
                        if (!Equals(current, original))
                        {
                            LogChangeDetected(entry, property, original, current);
                            entry.SetPropertyModified(property);
                        }
                    }
                    else
                    {
                        if (!comparer.Equals(current, original))
                        {
                            LogChangeDetected(entry, property, original, current);
                            entry.SetPropertyModified(property);
                        }
                    }
                }
            }

            foreach (var property in entityType.GetProperties())
            {
                DetectKeyChange(entry, property);
            }

            if (entry.HasRelationshipSnapshot)
            {
                foreach (var navigation in entityType.GetNavigations())
                {
                    DetectNavigationChange(entry, navigation);
                }
            }
        }
           

由以上代码可见。。

                    var current = entry[property];

                    var original = entry.GetOriginalValue(property);

主要是通过比较以上两个值来判断是否已修改

其中 GetProperties 扫了下相关的代码,,基本上就是一个属性袋的概念,,用有序字典来保存。

Entity 是当前值 

_values[index] = SnapshotValue(property, value); 是快照原始值

_values 是个 ISnapshot,,是个对象 从InternalEntityEntry生成的一个动态表达式树数组

这里看得有点朦,,不确定是否正确

return Expression.Lambda<Func<TInput, ISnapshot>>(
                    CreateConstructorExpression(entityType, parameter),
                    parameter)
                .Compile();
           

2 emit

emit 大约是要求实体类的属性需要带 virtual,,,否则不好用。。或许是我还没找到生成带new的方式吧。。

关键代码

            //动态创建类代理

            TypeBuilder typeBuilderProxy = moduleBuilder.DefineType($"{inType.Name}_Proxy_{inKey}", System.Reflection.TypeAttributes.Public, inType);

            PropertyBuilder propertyBuilder = typeBuilderProxy.DefineProperty("a", System.Reflection.PropertyAttributes.SpecialName, typeof(string), null);

            //FieldBuilder fieldBuilder = typeBuilderProxy.DefineField("_a", typeof(string), FieldAttributes.Private);

            //重写属性的Get Set方法

            var methodGet = typeBuilderProxy.DefineMethod("get_a" , GetSetMethodAttributes, typeof(string), Type.EmptyTypes);

            var methodSet = typeBuilderProxy.DefineMethod("set_a" , GetSetMethodAttributes, null, new Type[] { typeof(string) });

            var ilGetMethod = methodGet.GetILGenerator();

            ilGetMethod.Emit(OpCodes.Ret);

            //il of set method

            ILGenerator ilSetMethod = methodSet.GetILGenerator();

            ilSetMethod.Emit(OpCodes.Ret);

            //设置属性的Get Set方法

            propertyBuilder.SetGetMethod(methodGet);

            propertyBuilder.SetSetMethod(methodSet);

                //创建类实例

                var instance = Activator.CreateInstance(dict[inKey]);

                return (T)instance;

        private const System.Reflection.MethodAttributes GetSetMethodAttributes = System.Reflection.MethodAttributes.Public | System.Reflection.MethodAttributes.HideBySig

         | System.Reflection.MethodAttributes.NewSlot | System.Reflection.MethodAttributes.Virtual   | System.Reflection.MethodAttributes.SpecialName | System.Reflection.MethodAttributes.CheckAccessOnOverride

            ;

但这样写完后 发现 一直执行不到子类的方法,,一直是获取父类的方法,,不知道哪里写挂了。。还是因为3.0有bug

3、INotifyPropertyChanged

创建一个基类实现 INotifyPropertyChanged ,其它实体从这个基类继承。

4、Roslyc CSharpSyntaxTree

动态创建方式。。

但跟Emit一样,,强制转换为父级实体类型后,,无法监控属性变更。

总结:仿efCore方式才是实体ORM,属性监控的王道。其它用途则视情况选型。

仿EFcore实体ORM

主要是有个原值,缓存表。。

外面应该有个模型缓存表。

然后是上下文关联模型,关联实体,关联原值缓存表。

https://dev.tencent.com/u/jiaguoxinzhi/p/code_module/git/blob/master/LikeEfCore 此代码未成熟 不公开

继续阅读