本文从四个方面对Linq to sql动态查询进行了阐述,这其中既有原理,又有实例,是大家休学习Linq to sql动态查询的好资料。

创新互联建站专注为客户提供全方位的互联网综合服务,包含不限于成都网站建设、网站制作、沾益网络推广、小程序开发、沾益网络营销、沾益企业策划、沾益品牌公关、搜索引擎seo、人物专访、企业宣传片、企业代运营等,从售前售中售后,我们都将竭诚为您服务,您的肯定,是我们最大的嘉奖;创新互联建站为所有大学生创业者提供沾益建站搭建服务,24小时服务热线:13518219792,官方网址:www.cdcxhl.com
动态的生成sql语句,根据不同的条件构造不同的where字句,是拼接sql 字符串的好处。而Linq的推出,是为了弥补编程中的 Data != Object 的问题。我们又该如何实现用object的Linq to sql动态查询呢?
1,Linq to sql动态查询之用object的查询是什么?
我们可以简单的举这么一个例子。我们到公安局查找一个人。首先,我们会给出他的一些特征,比如,身高多少,年龄多少,性别,民族等。那么,我们把这个人的一些特征输入电脑。我们希望,电脑能给我们返回这个人的信息。
而实际上,有相同特征的人太多了,常常返回一个集合。那让我们把这个过程抽象到程式里。我们需要new出来一个对象。这个对象包含了我们能知道的基本信息。而后,把这个对象传给Linq To Sql,等待返回结果。
根据这些基本的需求,我们来定义下面的函数,为了实现这个函数对任何实体都是有用的,我们把它定义为generic的。为了不破坏Linq To Sql延迟加载的规矩,我们把它的返回类型定义为IQueryable。如下:
public IQueryable Find (TEntity obj) where TEntity : class
思路出来了,先new出来一个对象,然后把对象传给这个函数,我们渴望它能返回与这个对象匹配的结果集。为了让它和DataContext有关系,我们把这个函数放到DataContext的partial类里。
鼠标右击Linq To Sql文件,选择view code,这个时候,vs会为你创造一个DataContext的partial类,其扩展名比影射文件少了中间的desiger。大家要注意,你如果想自己修改影射文件,请放到这个文件里。这样当影射code被刷新时,才不会冲掉你自己的修改。先大体描述下我们的思路。
- NorthwindDataContext db = new NorthwindDataContext();
 - //先new出一个对象
 - Customer c = new Customer();
 - //添入我们知道的最基本的信息,可以从ui获得
 - c.City = "London";
 - c.Phone = "23236133";
 - //call函数find返回结果
 - var q = db.Find
 (c); 
2,Linq to sql动态查询之原理
Linq To Sql动态查询支持用户动态生成lambda表达式。本文中所实现的方法,正是反射加lambda动态表达式。我们先来看如何动态生成lambda表达式。
在 Linq 中,lambda表达式会首先转化为Expression Tree,本文并不详解Expression Tree。Expression Tree是lambda表达式从code的形式转化为data的结果,是一种更高效的在内存中的数据结构。比如:
- Func
 f = x => x + 1; // Code - Expression
 > e = x => x + 1; // Data 
第二个,其实也就是***个转化后的形式。那好了,有了这个前提,我们就可以动态构造这个Expression Tree了。
- // 先构造了一个ParameterExpression对象,这里的c,就是Lambda表达中的参数。(c=>)
 - ParameterExpression param = Expression.Parameter(typeof(TEntity), "c");
 - //构造表达式的右边,值的一边
 - Expression right = Expression.Constant(p.GetValue(obj, null));
 - //构造表达式的左边,property一端。
 - Expression left = Expression.Property(param, p.Name);
 - //生成筛选表达式。即c.CustomerID == "Tom"
 - Expression filter = Expression.Equal(left, right);
 - //生成完整的Lambda表达式。
 - Expression
 > pred = - Expression.Lambda
 >(filter, param); - //在这里,我们使用的是and条件。
 - queryquery = query.Where(pred);
 
3,Linq to sql动态查询之反射在本方法中的作用
因为我们采用了模板,也就是说,我们并不知道传进来的对象会有那些property,那反射在这里就提供一个很好的方法。我们可以通过反射去遍历每一个property,只有判断出该property的值不为null时,才将其视为条件。该函数完整的代码如下:
- public IQueryable
 Find (TEntity obj) where - TEntity : class
 - {
 - //获得所有property的信息
 - PropertyInfo[] properties =
 - obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
 - //构造初始的query
 - IQueryable
 query = - this.GetTable
 ().AsQueryable (); - //遍历每个property
 - foreach (PropertyInfo p in properties)
 - {
 - if (p != null)
 - {
 - Type t = p.PropertyType;
 - //加入object,Binary,和XDocument, 支持sql_variant,imager 和xml等的影射。
 - if (t.IsValueType || t == typeof(string) || t == typeof(System.Byte[])
 - || t == typeof(object) || t == typeof(System.Xml.Linq.XDocument)
 - || t == typeof(System.Data.Linq.Binary))
 - {
 - //如果不为null才算做条件
 - if ( p.GetValue(obj, null) != null)
 - {
 - ParameterExpression param = Expression.Parameter(typeof(TEntity), "c");
 - Expression right = Expression.Constant(p.GetValue(obj, null));
 - Expression left = Expression.Property(param, p.Name);
 - Expression filter = Expression.Equal(left,right);
 - Expression
 > pred = - Expression.Lambda
 >(filter, param); - queryquery = query.Where(pred);
 - }
 - }
 - }
 - }
 - return query;
 - }
 
4,Linq to sql动态查询之测试用例及反思
我们用下面的例子来测试下这个函数
- Customer c = new Customer();
 - c.City = "London";
 - c.Phone = "23236133";
 - var q = db.Find
 (c).ToList(); 
其生成的sql语句为:
- SELECT [t0].[CustomerID], [t0].[CompanyName],
 - [t0].[ContactName], [t0].[ContactTitle],
 - [t0].[Address], [t0].[City], [t0].[Region],
 - [t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0].[Fax]
 - FROM [dbo].[Customers] AS [t0]
 - WHERE ([t0].[Phone] = @p0) AND ([t0].[City] = @p1)
 - -- @p0: Input NVarChar (Size = 8; Prec = 0; Scale = 0) [23236133]
 - -- @p1: Input NVarChar (Size = 6; Prec = 0; Scale = 0) [London]
 
我们可以看到,其Linq to sql动态查询语句中,只有city和phone两个条件。并且他们之间是and的关系。我们最开始的设想实现了,但是,它是***的吗?如果是or条件该怎么办呢?更多的时候,我们是在用模糊查询,那又该怎么办呢?这个问题,就留于下篇。
***,介绍一种写log的方法。stream流使用static为避免多个datacontext的同时在使用log.txt文件。
- partial class DataMappingDataContext
 - {
 - private static StreamWriter sw =
 - new StreamWriter(Path.Combine(Directory.GetCurrentDirectory(), "log.txt"),
 - true);
 - /**////
 - /// Try to create DataContext with log.
 - /// summary>
 - /// param>
 - public DataMappingDataContext(bool withLog)
 - : this()
 - {
 - OnCreated();
 - if (withLog)
 - {
 - if (sw == null)
 - {
 - sw = new StreamWriter(Path.Combine(Directory.GetCurrentDirectory(),
 - "log.txt"), true);
 - }
 - this.Log = sw;
 - }
 - }
 - /**////
 - /// try to close streamwriter
 - /// summary>
 - /// param>
 - protected override void Dispose(bool disposing)
 - {
 - base.Dispose(disposing);
 - sw.Flush();
 - }
 - }
 - 在dispose函数里,把输出流flush。使用时,如下
 - using(northwind db = new norhwind(true))
 - {
 - //do something......
 - }
 
以上就是笔者和大家分享的关于Linq to sql动态查询的知识。
Copyright © 2009-2022 www.wtcwzsj.com 青羊区广皓图文设计工作室(个体工商户) 版权所有 蜀ICP备19037934号