学习笔记 Linq to sql动态查询

开发 后端
Linq的推出,是为了弥补编程中的 Data != Object 的问题。我们又该如何实现用object的Linq to sql动态查询呢?本文作者将对此作出介绍。

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

动态的生成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被刷新时,才不会冲掉你自己的修改。先大体描述下我们的思路。

  1. NorthwindDataContext db = new NorthwindDataContext();  
  2. //先new出一个对象  
  3. Customer c = new Customer();  
  4. //添入我们知道的最基本的信息,可以从ui获得  
  5. c.City = "London";  
  6. c.Phone = "23236133";  
  7. //call函数find返回结果  
  8. var q = db.Find<Customer>(c);  

2,Linq to sql动态查询之原理

Linq To Sql动态查询支持用户动态生成lambda表达式。本文中所实现的方法,正是反射加lambda动态表达式。我们先来看如何动态生成lambda表达式。

在 Linq 中,lambda表达式会首先转化为Expression Tree,本文并不详解Expression Tree。Expression Tree是lambda表达式从code的形式转化为data的结果,是一种更高效的在内存中的数据结构。比如:

  1. Func<int,int> f = x => x + 1; // Code  
  2. Expression<Func<int,int>> e = x => x + 1; // Data  

第二个,其实也就是***个转化后的形式。那好了,有了这个前提,我们就可以动态构造这个Expression Tree了。

  1. // 先构造了一个ParameterExpression对象,这里的c,就是Lambda表达中的参数。(c=>)   
  2. ParameterExpression param = Expression.Parameter(typeof(TEntity), "c");  
  3. //构造表达式的右边,值的一边  
  4. Expression right = Expression.Constant(p.GetValue(obj, null));  
  5. //构造表达式的左边,property一端。  
  6. Expression left = Expression.Property(param, p.Name);  
  7. //生成筛选表达式。即c.CustomerID == "Tom"  
  8. Expression filter = Expression.Equal(left, right);  
  9. //生成完整的Lambda表达式。  
  10. Expression<Func<TEntity, bool>> pred = 
  11. Expression.Lambda<Func<TEntity, bool>>(filter, param);  
  12. //在这里,我们使用的是and条件。  
  13. queryquery = query.Where(pred);  

3,Linq to sql动态查询之反射在本方法中的作用

因为我们采用了模板,也就是说,我们并不知道传进来的对象会有那些property,那反射在这里就提供一个很好的方法。我们可以通过反射去遍历每一个property,只有判断出该property的值不为null时,才将其视为条件。该函数完整的代码如下:

  1. public IQueryable<TEntity> Find<TEntity>(TEntity obj) where
  2.  TEntity : class  
  3. {  
  4. //获得所有property的信息  
  5. PropertyInfo[] properties = 
  6. obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);  
  7. //构造初始的query  
  8. IQueryable<TEntity> query = 
  9. this.GetTable<TEntity>().AsQueryable<TEntity>();  
  10. //遍历每个property  
  11. foreach (PropertyInfo p in properties)  
  12. {  
  13. if (p != null)  
  14. {  
  15. Type t = p.PropertyType;  
  16. //加入object,Binary,和XDocument, 支持sql_variant,imager 和xml等的影射。  
  17. if (t.IsValueType || t == typeof(string) || t == typeof(System.Byte[])  
  18. || t == typeof(object) || t == typeof(System.Xml.Linq.XDocument)  
  19. || t == typeof(System.Data.Linq.Binary))  
  20. {  
  21. //如果不为null才算做条件  
  22. if ( p.GetValue(obj, null) != null)  
  23. {  
  24. ParameterExpression param = Expression.Parameter(typeof(TEntity), "c");  
  25. Expression right = Expression.Constant(p.GetValue(obj, null));  
  26. Expression left = Expression.Property(param, p.Name);  
  27. Expression filter = Expression.Equal(left,right);  
  28. Expression<Func<TEntity, bool>> pred = 
  29. Expression.Lambda<Func<TEntity, bool>>(filter, param);  
  30. queryquery = query.Where(pred);  
  31. }  
  32. }  
  33. }  
  34. }  
  35. return query;  
  36. }  

4,Linq to sql动态查询之测试用例及反思

  我们用下面的例子来测试下这个函数

  1. Customer c = new Customer();  
  2. c.City = "London";  
  3. c.Phone = "23236133";  
  4. var q = db.Find<Customer>(c).ToList();  

其生成的sql语句为:

  1. SELECT [t0].[CustomerID], [t0].[CompanyName],
  2.  [t0].[ContactName], [t0].[ContactTitle],
  3.  [t0].[Address], [t0].[City], [t0].[Region],
  4.  [t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0].[Fax]  
  5. FROM [dbo].[Customers] AS [t0]  
  6. WHERE ([t0].[Phone] = @p0) AND ([t0].[City] = @p1)  
  7. -- @p0: Input NVarChar (Size = 8Prec = 0Scale = 0) [23236133]  
  8. -- @p1: Input NVarChar (Size = 6Prec = 0Scale = 0) [London]  
  9.  

我们可以看到,其Linq to sql动态查询语句中,只有city和phone两个条件。并且他们之间是and的关系。我们最开始的设想实现了,但是,它是***的吗?如果是or条件该怎么办呢?更多的时候,我们是在用模糊查询,那又该怎么办呢?这个问题,就留于下篇。

***,介绍一种写log的方法。stream流使用static为避免多个datacontext的同时在使用log.txt文件。

  1.   partial class DataMappingDataContext  
  2. {  
  3. private static StreamWriter sw = 
  4. new StreamWriter(Path.Combine(Directory.GetCurrentDirectory(), "log.txt"),
  5. true);  
  6. /**//// <summary> 
  7. /// Try to create DataContext with log.  
  8. /// summary> 
  9. /// <param name="withLog">param> 
  10. public DataMappingDataContext(bool withLog)  
  11. : this()  
  12. {  
  13. OnCreated();  
  14. if (withLog)  
  15. {  
  16. if (sw == null)  
  17. {  
  18. sw = new StreamWriter(Path.Combine(Directory.GetCurrentDirectory(),
  19.  "log.txt"), true);  
  20. }  
  21. this.Log = sw;  
  22. }  
  23. }  
  24. /**//// <summary> 
  25. /// try to close streamwriter  
  26. /// summary> 
  27. /// <param name="disposing">param> 
  28.         protected override void Dispose(bool disposing)  
  29. {  
  30. base.Dispose(disposing);  
  31. sw.Flush();  
  32. }  
  33. }  
  34.   在dispose函数里,把输出流flush。使用时,如下  
  35. using(northwind db = new norhwind(true))  
  36. {  
  37. //do something......  
  38. }  

以上就是笔者和大家分享的关于Linq to sql动态查询的知识。

【编辑推荐】

  1. 深入浅出 LINQ表达式
  2. LINQ基础学习之LINQ to XML
  3. 学习心得LINQ to XML
  4. 浅析LINQ开发技术之LINQ to XML
  5. 详细阐述linq动态排序
责任编辑:阡陌 来源: IT168
相关推荐

2009-09-18 15:15:12

LINQ to SQL

2009-09-17 16:46:34

Linq to sql

2009-09-16 13:02:12

LINQ查询子句

2009-09-15 10:46:04

LINQ to SQL

2009-09-15 10:16:01

LINQ动态查询

2009-09-15 09:19:22

linq动态条件

2009-09-15 16:52:19

Linq To Dat

2009-09-08 17:57:54

LINQ to Dat

2009-09-18 14:33:37

LINQ to SQLSQL命令

2009-09-07 17:09:45

Linq To Sql

2009-09-11 12:08:09

Linq to SQL

2009-09-14 19:14:51

LINQ动态查询

2009-09-17 17:03:13

LINQ动态查询

2009-09-15 09:45:23

Linq动态条件

2009-09-17 18:05:15

linq to sql

2009-09-14 17:10:57

LINQ模糊查询

2009-09-17 15:51:39

Linq to sql

2009-09-08 09:12:12

LINQ构建框架设计

2009-09-17 08:47:00

Linq查询

2009-09-14 19:20:22

LINQ TO SQL
点赞
收藏

51CTO技术栈公众号