Linq to Entity经验:表达式转换
http://www.cnblogs.com/ASPNET2008/archive/2012/10/27/2742434.html
最近一年的项目,我主要负责一些小型项目(就是指企业内部的小项目),在数据库操作方面我们采用了以开发速度快为特点的Linq to Entity,这里我不多讲它的使用方法,先来分享下我认为还不错的几个地方:
1:某种情况下可以完全代替传统SQL开发
这里是指比较简单的数据库处理,比如查询,几个表关联查询及添加数据,更新数据,删除数据等,不包含特别复杂的事务处理或者业务逻辑特别复杂的小型报表之类的处理,为此不需要员工一定会SQL语句的开发。
2:性能上也是能接受的
现在的Entity Framework5,微软已经做出大量的优化工作,专门针对如何生成查询更优的SQL语句做了大量努力,且一般小型项目也不会存在特别大的性能问题。大家发现问题了可以看下生成的SQL做特殊优化即可。
3:简化了开发过程
一般情况下,我们首先需要将数据库表数据加载成DataReader或者是DataTable,然后再转换成我们的业务数据Model,有了EntityFrame work,它已经自动完成了此部分的转换。
问题:
如何处理数据库Model以及业务数据Model表达式之间的转换?
什么是数据库Model?
当我们采用数据库优先方式创建了一个edmx文件后,它会生成和数据库表名一样的数据库Model,比如我这里的DataAccess.ActionInfo
什么是业务数据Model?
真正的业务系统中,是不能直接使用系统自动生成的Model的,原因如下:
1:这些代码是生动生成的,随时会发生改变,稳定性太差。
2:数据库Model完全和数据库表对应,而业务数据Model有可能和数据库模型不完全一致,或者完全不一样。业务数据Model是处理业务逻辑的一个
数据载体,由它解析成不同的数据库Model,最近进行数据库操作。比如我这里的ObjectModel.ActionInfo
前几篇文章中(我所理解的IRepository(续) ,我所理解的IRepository ),我提到我们项目中定义了如下仓储接口用于数据库查询。
IList<T> QueryByPage<TKey>(Expression<Func<T, bool>> filter, Expression<Func<T, TKey>> orderBy,int orderType, int pageSize, int pageIndex, out int recordsCount);
它的条件接受一个表达式,由于UI屋以及业务逻辑层均只能调用业务数据Model,当进行数据库查询时,EntityFramwork只能接受参数类型为
数据库Model的对象,所以这里我们需要将类型为业务数据Model的表达式能够自动的转换成数据库Model类型的表达式。
比如我们在UI层可以这样查询数据,这里p的类型是业务数据Model
service.QueryByPage(p => (p.IsActive && p.FunctionInfoId == FunctionInfoId.Value), p => p.Id, 1, pageSize, pageIndex.Value + 1, out recordCount);
下面是我们的业务数据Model,包含一些MVC的数据验证特性标签,同时字段数量上也和表字段不相同。
下面是生成的数据库Model,代码较多,这里就贴一个属性内容,主要都是些和数据相关的内容,比如外键关系等:
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.String Name
{
get
{
return _Name;
}
set
{
OnNameChanging(value);
ReportPropertyChanging("Name");
_Name = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("Name");
OnNameChanged();
}
}
我们需要一个工具类能够完成这两种不同类型的表达式之间的类型转换,需要满足如下需求:
1:最简单的表达式条件
对属性做直接的条件比较,比如:等于,不等于,大于,小于,或 这里二元操作符。
比如:p=>p.Name==1, p=>p.Name==1||p.Name==2
2:需要支持部分函数
如果我们想做某个字段的模糊查询,在SQL中是用Like语句,在.net中我们可以调用StartWith,EndWith,Contains方法来完成
比如:p=>p.Name.StartWith("1")
解决思路:
表达式树一旦创建了它是不能修改其内容的,我们只能重新创建一个表达式树,所以我们的工作就是解析源表达式树,然后构造自己的表达式树,在构建过程后也就完成类型的转换。
首先需要创建一个工具类用于转换:
TToB:指最终转换成的类型,我们这里就直接理解为数据库Model
TR:就是表达式的返回值
TFrom:指源对象类型
核心就是调用ConvertNode方法进入表达式的解析。
public class ExpressionConverter<TToB>
{
public static Expression<Func<TToB, TR>> Convert<TFrom, TR>(Expression<Func<TFrom, TR>> expr)
{
Dictionary<Expression, Expression> substitutues = new Dictionary<Expression, Expression>();
var oldParam = expr.Parameters[0];
var newParam = Expression.Parameter(typeof(TToB), oldParam.Name);
substitutues.Add(oldParam, newParam);
Expression body = ConvertNode(expr.Body, substitutues);
return Expression.Lambda<Func<TToB, TR>>(body, newParam);
}
}
需求1的解决方案:
对于普通的条件,无非就是一些二元操作,所以我们只要了解下ExpressionType的内容,然后根据不同的类型做不同的解析即可,比如处理二元表达式:下面文章中列表出各种ExpressionType的详细解释: http://technet.microsoft.com/zh-cn/library/bb361179(en-us,VS.90).aspx
需求2解决方案:
对于这部分有函数调用的地方,我们需要做特殊处理,目前只处理常用的Contains,StartWith,EndWith,其它的函数也可以继续做解析。
补充:
除了上面的二元表达式,方法调用表达式外,还有几个表达式也是重点:
1:ParameterExpression,即参数表达式,比如表达式p=>p.IsActive 这里的{p}就是一个参数表达式
2:ConstantExpression,即常量表达式,比如表达式p=>p.Name==1 这里的1就是常量表达式
3:MemberExpression,即成员表达式,比如p.Name,这一步的操作我们能够实现业务数据Model与数据库Model之间的类型转
换,它的原理就是比较成员是否一样,这里包括属性名称,属性类型等,有点类似反射,一个一个比,遇到相同的就赋值。
总结:
表达式树虽然看起来不太容易使用,但只要明白它的一些基本用法就能解决你的大部分问题,重点就是需要了解如何解析表达式树。
Linq to Entity经验:表达式转换的更多相关文章
- Linq to Entity中连接两个数据库时要注意的问题
Linq to Entity中连接两个数据库时要注意的问题 今天大学同学问了我一个问题,Linq to Entity中连接两个数据库时,报错“指定的 LINQ 表达式包含对与不同上下文关联的查询的引用 ...
- LINQ(隐式表达式、lambda 表达式)
.NET 中一项突破性的创新是 LINQ(Language Integrated Query,语言集成查询),这组语言扩展让你能够不必离开舒适的 C# 语言执行查询. LINQ 定义了用于构建查询表达 ...
- lambda表达式转换sql
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; usin ...
- EF架构~linq to entity的随机排序问题
回到目录 对于从linq to sql迁移过来的开发者,对随机排序不会感到陌生,直接为datacontext添加一个方法再配合反射就可以实现随机排序了,代码如下: /// <summary> ...
- EF架构~在Linq to Entity中使用日期函數
回到目录 眾所周知,在linq to entity的查询语句中,不允许出现ef不能识别的关键字,如Trim,Substring,TotalDays等.net里的关键字,在EF查询里都是不被支持的,它的 ...
- C# Linq to Entity 多条件 OR查询
技术背景:框架MVC,linq to Entity 需要一定的lambda书写能力 问题:在简单的orm中完成一些简单的增删查改是通过where insert delete update 完成的,但是 ...
- 计算器类(C++&JAVA——表达式转换、运算、模板公式)
运行: (a+b)*c 后缀表达式:ab+c* 赋值: Enter the a : 10 Enter the b : 3 Enter the c : 5 结果为:65 代码是我从的逻辑判断系统改过来的 ...
- ZH奶酪:Python 中缀表达式转换后缀表达式
实现一个可以处理加减乘数运算的中缀表达式转换后缀表达式的程序: 一个输入中缀表达式inOrder 一个输出池pool 一个缓存栈stack 从前至后逐字读取inOrder 首先看一下不包含括号的: ( ...
- Linq快速入门——Lambda表达式的前世今生
Linq快速入门——Lambda表达式的前世今生 Lambda表达式其实并不陌生,他的前生就是匿名函数,所以要谈Lambda表达式,就不得不谈匿名函数,要谈匿名函数,那又要不得不谈委托. 何为委托 ...
随机推荐
- .NET/android/java/iOS AES通用加密解密(修正安卓)
移动端越来越火了,我们在开发过程中,总会碰到要和移动端打交道的场景,比如.NET和android或者iOS的打交道.为了让数据交互更安全,我们需要对数据进行加密传输.今天研究了一下,把几种语言的加密都 ...
- 常用js字符串方法学习总结
2016-06-15 js数组和字符串方法有很多,并且有一部分在使用的过程中有很多方法是很容易被混淆的,今天来总结一下js中数组和字符串的方法. ♦数组(Array)的方法 1.push() 和 po ...
- Javascript常用方法函数收集(一)
1.字符串长度截取 function cutstr(str, len) { var temp, icount = 0, patrn = /[^\x00-\xff]/, strre = "&q ...
- MFC绘制图片闪烁详解
用MFC如何高效地绘图 显示图形如何避免闪烁,如何提高显示效率是问得比较多的问题. 而且多数人认为MFC的绘图函数效率很低,总是想寻求其它的解决方案. MFC的 ...
- Android数据存储-读取内部存储空间数据
内部存储空间的默认位置 data/data/应用名称 写数据,获取FileOutPutStream的方式 1.直接写死路径的方式 FileOutputStream fos = new FileOutp ...
- google vr开源 cardboard
https://developers.google.com/cardboard/android/ 待续
- [转帖]网络协议封封封之Panabit配置文档
原帖地址:http://myhat.blog.51cto.com/391263/322378
- 常用 Java 静态代码分析工具的分析与比较
常用 Java 静态代码分析工具的分析与比较 简介: 本文首先介绍了静态代码分析的基 本概念及主要技术,随后分别介绍了现有 4 种主流 Java 静态代码分析工具 (Checkstyle,FindBu ...
- Xcode 的一些调式技巧
XCode 内置GDB,我们可以在命令行中使用 GDB 命令来调试我们的程序.下面将介绍一些常用的命令以及调试技巧. po 命令:为 print object 的缩写,显示对象的文本描述(显示从对象的 ...
- PARSEC-3.0编译错误
OS: Ubuntu 14.04 LTS (x86_64) ***error 1 OpenSSL 1.0.1e 与 perl5.18 不兼容 POD document had syntax error ...