EntityFramework Core查询数据基本本质

【导读】在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使用到炉火纯青地步,那么自身整体核心竞争力将更上一台阶。