应无所住,而生其心
排名
6
文章
6
粉丝
16
评论
8
{{item.articleTitle}}
{{item.blogName}} : {{item.content}}
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2024TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术

扩展ef自动映射需要查询的字段(表达式树Expression),动态构建返回值

10411人阅读 2019/3/29 10:55 总访问:4816125 评论:1 收藏:0 手机
分类: EF

Entity Framework 动态构造select表达式

比如我们需要返回某些字段会采用如下的写法

但是发现每次都去写select如果字段很多不想去一个一个查询出来,就想指定一个dto的类型

他就能查询dto里边的字段,然后自动映射到dto里边去就可以减少很多工作量了


我们把lambda表达式提到外面去

这种可以,但是下面这种构建一个dto_user怎么都不行要报错

其实把表达式变成func就可以了


或者调用表达式树的Compile方法生成func当然也是一样的

有了这个就可以通过类型+反射动态构建查询的字段了

测试的原型


测试成功!很高兴于是去封装了一个通用的扩展方法!


用法:

这样就会自动映射DTO_User了,写出来了还是很激动


但是很快就发现问题了,他居然是查询的全部!,然后那个查询需要字段的他居然是在内存中操作了,

每次都会查询全部字段出来

其实这个扩展方法实现了动态拷贝,可以作为解决这个问题的第二个步骤,把需要的字段查询出来后

在进行动态拷贝,平时进行对象转化的时候也可以直接用


然后测试发现select如果传表达式树他会去解析成sql,他会转换成需要查询的字段sql

从返回的IQueryable接口就知道,他是会生成的sql的,但是如果我们传递的是Func呢

返回的却是IEnumerable,当然是在内存中操作的了,

 数据库查询只有IEnumerable才回执行到数据库

IQueryable只拼接sql 


因为func只能在里边当作方法去执行

而表达式树确可以得到很多东西比如参数返回值什么的

这也是他们的区别



想要真正实现自动映射到DTO,而且只查询的还是那几个字段,那么这里要想办法动态创建表达式树,

不能直接传func

这就需要了解ef内部是怎么解析的这个表达式树,还有表达式树是怎么动态生成的了


使用MemberInitExpression就可以动态构建需要的表达式树


msdn上面的资料

https://msdn.microsoft.com/zh-cn/library/system.linq.expressions.memberinitexpression.aspx

class Animal
{
    public string Species {get; set;}
    public int Age {get; set;}
}
 
public static void CreateMemberInitExpression()
{
    System.Linq.Expressions.NewExpression newAnimal =
        System.Linq.Expressions.Expression.New(typeof(Animal));
 
    System.Reflection.MemberInfo speciesMember =
        typeof(Animal).GetMember("Species")[0];
    System.Reflection.MemberInfo ageMember =
        typeof(Animal).GetMember("Age")[0];
 
    // Create a MemberBinding object for each member
    // that you want to initialize.
    System.Linq.Expressions.MemberBinding speciesMemberBinding =
        System.Linq.Expressions.Expression.Bind(
            speciesMember,
            System.Linq.Expressions.Expression.Constant("horse"));
    System.Linq.Expressions.MemberBinding ageMemberBinding =
        System.Linq.Expressions.Expression.Bind(
            ageMember,
            System.Linq.Expressions.Expression.Constant(12));
 
    // Create a MemberInitExpression that represents initializing
    // two members of the 'Animal' class.
    System.Linq.Expressions.MemberInitExpression memberInitExpression =
        System.Linq.Expressions.Expression.MemberInit(
            newAnimal,
            speciesMemberBinding,
            ageMemberBinding);
 
    Console.WriteLine(memberInitExpression.ToString());
 
    // This code produces the following output:
    //
    // new Animal() {Species = "horse", Age = 12}
}


改进下:使用参数来赋值


 未完待续。。。



欢迎加群讨论技术,群:677373950(满了,可以加,但通过不了),2群:656732739

评价