【导读】在EntityFramework Core中、当查询出数据后,是如何将数据映射给实体的呢?本节我们预先做个基本探讨,后续给出其底层原理本质
前不久,我们在探索性能时,给出利用反射达到性能瓶颈时的方案即使用委托,如下:
var setId = (Action<Test, int>)Delegate.CreateDelegate(typeof(Action<Test, int>), null, typeof(Test).GetProperty("Id").GetSetMethod());
上述我们通过委托方式来代替反射,可能我们也想到了另外一种方案,通过lambda构建表达式的方式
查询数据基本本质
首先我们来看看如何手动构建lambda表达式来获取或设置数据,废话不多讲,直接见代码
public static Action<T, object> Set<T>(PropertyInfo propertyInfo)
{var targetType = propertyInfo.DeclaringType;var setMethod = propertyInfo.GetSetMethod();var type = propertyInfo.PropertyType;var target = Expression.Parameter(targetType, "t");var value = Expression.Parameter(typeof(object), "d");var condition = Expression.Condition(Expression.Equal(value, Expression.Constant(DBNull.Value)),Expression.Default(type),Expression.Convert(value, type));var body = Expression.Call(Expression.Convert(target, setMethod.DeclaringType),setMethod,condition);return Expression.Lambda<Action<T, object>>(body, target, value).Compile();
}
当我们获取到数据库数据时,紧接着需要将其对应列数据赋值给对应属性,此时根据列类型需构建表达式判断条件(Condition),继而调用其设置方法,最后构建整体lambda进行编译执行,对于获取基本同理,不再解释
public static Func<T, object> Get<T>(PropertyInfo propertyInfo)
{var targetType = propertyInfo.DeclaringType;var getMethod = propertyInfo.GetGetMethod();var target = Expression.Parameter(targetType, "t");var body = Expression.Convert(Expression.Call(target, getMethod), typeof(object));return Expression.Lambda<Func<T, object>>(body, target).Compile();
}
那么问题来了,手动构建lambda表达式和上述直接通过创建委托方式,哪种方式更佳呢?
单从代码量上和所给例子来看,理论上是利用创建委托方式更佳,但是其潜在的问题是,通过创建委托,我们必须遍历实体所有属性,那么像上述利用lambda表达式难道就不用了?
事实上,完全不用,手动构建lambda的好处在于,我们可手动构建实体所有属性,然后一次性赋值从而改善性能
至于如何一次性获取对应实体所有属性,然后手动构建lambda并赋值,这才是EntityFramework Core的妙处设计所在,后续文章我会详细给出
手动构建lambda的场景很多,再比如构建自动化脚本,对lambda使用到炉火纯青地步,那么自身整体核心竞争力将更上一台阶
???? 是的,我的文章都是建立在基础上的一点额外探索,比如微服务、k8s等等流行的玩意当前还完全没有涉及,一来实际项目中,还未应用,二是,不愿浅尝辄止,意义不大。万变不离其宗,所有我们看过的代码难道不都是语法组合吗?