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表达式,就不得不谈匿名函数,要谈匿名函数,那又要不得不谈委托. 何为委托 ...
随机推荐
- little tips of painter.drawRect in Qt
一个QImage或QPixmap新建变量时,第一次填充图片时设置的宽高正常(fill),其后的绘制操作(draw)则会在绘制的矩形底边和右边加上painter.pen().width() 在下面代码1 ...
- 2014年7月份第1周51Aspx源码发布详情
QF万能视频播放器源码 2014-6-30 [VS2010]本源码是一个万能视频播放器源码.可实现各种格式的影片播放功能. 1.点击[开始]按钮,弹出窗口,选择影片路径,确定后即可播放.可拖拽滚 ...
- 使用TypeScript开发
学习过一段时间CoffeeScript,然后再学习TypeScript,最后还是决定使用TypeScript开发. CofeeScript主要是给js添加一些语法糖,编写代码要快捷的多,少量的代码开发 ...
- Adaboost 算法
一 Boosting 算法的起源 boost 算法系列的起源来自于PAC Learnability(PAC 可学习性).这套理论主要研究的是什么时候一个问题是可被学习的,当然也会探讨针对可学习的问题的 ...
- C#的New关键字的几种用法
一.在C#中,new这个关键字使用频率非常高,主要有3个功能: a) 作为运算符用来创建一个对象和调用构造函数. b) 作为修饰符. c) 用于在泛型声明中约束可能用作类型参 ...
- RainCup_No.1
Rain杯No.1 初见篇 本系列故事以及人名地名等纯属虚构,如有雷同,纯属巧合 在极东之地,有一个岛国,与岛国隔了一个海域有一个古老的国度,天朝.天朝T镇有个少年叫小S,故事从小S与少女Rain的相 ...
- google vr开源 cardboard
https://developers.google.com/cardboard/android/ 待续
- POJ2653判断直线是否相交
bool judge(node p1,node p2,node p3,node p4){ if(min(p1.x,p2.x)>max(p3.x,p4.x)||min(p1.y,p2.y)& ...
- 10大白帽黑客专用的 Linux 操作系统
原文出处: Irshad Pathoor 译文出处:Linux中国 欢迎分享原创到伯乐头条 今天让我们来介绍十个黑客专用的操作系统,它们被白帽黑客用作渗透测试的工具.这里我把 Kali Lin ...
- C#常用操作类库一(验证类)
public class Validator { #region 验证输入字符串为数字 /// <summary> /// 验证输入字符串 ...