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表达式,就不得不谈匿名函数,要谈匿名函数,那又要不得不谈委托. 何为委托 ...
随机推荐
- OGG for DB2 z/OS 12.2版本发布
2016-04-15 Oracle发布了GoldenGate for DB2 z/OS 12.2.0.1.2.可以从OTN或eDelivery下载,该版本是ogg for DB2 z/OS的第一个1 ...
- JDBC代码示例
package test; import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;imp ...
- 线程的Abort方法有感
今天看CSDN上一个很老的帖子,有个人说Thread.Abort()方法调用之后一定会抛出异常,我对这个有点疑问. 于是自己做了一个测试demo,来研究Abort抛出异常的时机.废话少说,直接上代码: ...
- Webdriver设置Chrome属性
1. ChromeDriver加载插件 File file = new File ("files\\youtube.crx"); ChromeOptions options = n ...
- 【转】Sqlite 混合模式程序集是针对“v2.0.50727”版的运行时生成的,在没有配置其他信息的情况下,无法在 4.0 运行时中加载该...
开发环境: vs2010+.net framework 4.0+ System.Data.SQLite.DLL (2.0)今天在做Sqlite数据库测试,一运行程序在一处方法调用时报出了一个异常 混合 ...
- Tomcat8 localhost+端口可以访问Manager APP,而IP+端口不可以访问 解决办法
localhost + 端口可以正常访问Manager APP,而IP + 端口不能访问Manager APP,报403错误.(我的主机环境是Ubuntu16.04) 前提是你已经配好了tomcat_ ...
- Doherty Threshold
Prior to the publication of the IBM technical paper behind what commonly known today as the Doherty ...
- Mongodb在Linux下安装及配置
1.下载mongodb的linux版本(注意32位和64位的区别),下载地址:http://www.mongodb.org/downloads 2.将下载的mongodb安装文件mongodb-lin ...
- 修改安卓串口蓝牙app问题记录
* 在网上下载的安卓的蓝牙串口app都是基于eclipse的,但往as里边导入时都存在问题. 迫不得已最后我使用的办法还是在as下面新建工程,然后把相关文件导入.不过还是遇到了其他的问题. * 某个蓝 ...
- Sqoop使用手册
转载请注明出处:http://www.cnblogs.com/xiaodf/ 1 Sqoop概述 2 版本说明 3 驱动安装 3.1 MySQL 4 基本用法 4.1 导入 4.1.1 保护密码 4. ...