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;
///
/// 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.
///
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>(
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 此代码未成熟 不公开