Linq To Sql进阶系列(七)动态查询续及CLR与SQL在某些细节上的差别
2008-11-05 11:30
423 查看
在上面一篇文章Linq To Sql进阶系列(六)中,我们提到了使用object的动态查询。本文在上文的基础上,再做更加深入的引申。同时修正上文中一些不妥的地方。
1, object的动态查询续
首先要做的事情,就是将Find的函数改成扩展方法。扩展方法只能放在静态类里,而且它的第一个参数必须带this关键字。在上文中,作者留下了一个迷题。当需要or条件时,又该如何做呢?本文也将这个问题给出回答。但是对于动态Like的条件,笔者依然还没有找到一个较好的方法。为了增加or条件,函数的声明也再一次被改动。如下:
public static IQueryable<TEntity> Find<TEntity>(this IQueryable<TEntity> source, TEntity obj, bool isAnd) where TEntity : class
在上文中,我们还碰到了System.Nullable<int>此类类型不支持的问题。其实这个地方主要原因在于我们构造right端的Expression Tree时,没有给它参数。那么这个问题通过Expression right = Expression.Constant(p.GetValue(obj, null), p.PropertyType); 可以得到修复。那整个函数修改后,如下:
public static IQueryable<TEntity> Find<TEntity>(this IQueryable<TEntity> source, TEntity obj, bool isAnd) where TEntity : class
在这里,首先检查输入的参数是否为null。扩展方法其实是按静态方法执行的。它和静态方法唯一不同的就是系统自动为其加了一个Attribute,而这个Attribute只能通过在第一个参数加this关键字才能获得。而后,在影射类型上,修改后的函数只支持数值型和string型。其原因就是像imager等并不支持条件查询。为了简化,我们只支持数值型和string型。这里最大的变化莫过于支持or条件了。调用Expression.And或Expression.Or就可以了。还有一个变化就是ParameterExpression对象和Expression<Func<TEntity, bool>>被移出了foreach循环。这样,提高了效率,只是在最后才去生成条件。
而实际上,大家大多使用是and条件,那再重载一个方法。
public static IQueryable<TEntity> Find<TEntity>(this IQueryable<TEntity> source, TEntity obj) where TEntity : class
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].[City] = @p0) AND ([t0].[Country] = @p1)
-- @p0: Input NVarChar (Size = 6; Prec = 0; Scale = 0) [London]
-- @p1: Input NVarChar (Size = 2; Prec = 0; Scale = 0) [UK]
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].[City] = @p0) OR ([t0].[Country] = @p1)
ORDER BY [t0].[Country]
-- @p0: Input NVarChar (Size = 6; Prec = 0; Scale = 0) [London]
-- @p1: Input NVarChar (Size = 2; Prec = 0; Scale = 0) [UK]
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].[City] = @p0) AND ([t0].[Country] = @p1)
ORDER BY [t0].[CustomerID]
-- @p0: Input NVarChar (Size = 6; Prec = 0; Scale = 0) [London]
-- @p1: Input NVarChar (Size = 2; Prec = 0; Scale = 0) [UK]
2,限定字段在某集合中
这有点像in操作。比如where city in ('London', 'BeiJing') 也可以写成 where city = 'London' or city = 'BeiJing'。既然谈到or条件的动态构造了,那就也来构造下这个吧。看上去有点多此一举。但是,至少是个很好的学习机会。这个和上面不同的是,它条件字段是唯一的,变化的是该字段的值。那用一string将字段名成传入,并用一集合将字段值传入函数。
该函数完整的定义入下:
public static IQueryable<TEntity> WhereOr<TEntity, OrType>(this IQueryable<TEntity> source, string propertyName, IEnumerable<OrType> values)
SELECT [t0].[EmployeeID], [t0].[LastName], [t0].[FirstName], [t0].[Title], [t0].
[TitleOfCourtesy], [t0].[BirthDate], [t0].[HireDate], [t0].[Address], [t0].[City
], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[HomePhone], [t0].[Ext
ension], [t0].[Photo], [t0].[Notes], [t0].[ReportsTo], [t0].[PhotoPath]
FROM [dbo].[Employees] AS [t0]
WHERE [t0].[Region] IS NULL
Linq To Sql是通过Ado.Net于Sql打交道的。也就是说Linq To Sql是建立在CLR基础上的。这点细小的差别让Linq To Sql不知道该与谁保持平行。 Where条件中,有 == 和Equal两个方法,它们在Linq To Sql中是不一样的。Equal认为null是相等的。但是sql又不能用=来判断,所以Equal方法翻译的sql语句就有些长。请大家自己仔细比较下面两个语句的sql差别
var q5 = (from e in db.Employees
from o in db.Orders
where e.Region == o.ShipRegion
select new { e.Region, o }).ToList();
var q6 = (from e in db.Employees
from o in db.Orders
where Equals(e.Region, o.ShipRegion)
select new { e.Region, o }).ToList();
CLR和SQL在数值精度上的差别,也常让CLR抛OverFlow异常.这个很好判断,如果Ado.Net抛这个异常了,那Linq To Sql肯定要抛,所以并不是Linq To Sql的问题。
本文所提到代码,请到此下载完整版本.
相关文章:
C# 3.0 入门系列(一)
C# 3.0入门系列(二)
C# 3.0入门系列(三)
C# 3.0入门系列(四)-之Select操作
C#3.0入门系列(五)-之Where操作
C#3.0入门系列(六)-之OrderBy操作
C#3.0入门系列(七)--之OR工具介绍
C#3.0入门系列(八)-之GroupBy操作
C#3.0入门系列(九)-之GroupBy操作
C#3.0入门系列(十)-之Join操作
C#3.0入门系列(十一)-之In, Like操作
C#3.0入门系列(十二)-Lambda表达式中Lifting
C# 3.0与Linq To Sql的学习方法--浅谈
Linq To Sql进阶系列(一)-从映射讲起
Linq To Sql进阶系列(二)M:M关系
Linq To Sql进阶系列(三)CUD和Log
Linq To Sql进阶系列(四)User Define Function篇
Linq To Sql进阶系列(五)Store Procedure篇
Linq To Sql进阶系列(六)用object的动态查询与保存log篇
TrackBack:http://www.cnblogs.com/126/archive/2007/09/23/902920.html
1, object的动态查询续
首先要做的事情,就是将Find的函数改成扩展方法。扩展方法只能放在静态类里,而且它的第一个参数必须带this关键字。在上文中,作者留下了一个迷题。当需要or条件时,又该如何做呢?本文也将这个问题给出回答。但是对于动态Like的条件,笔者依然还没有找到一个较好的方法。为了增加or条件,函数的声明也再一次被改动。如下:
public static IQueryable<TEntity> Find<TEntity>(this IQueryable<TEntity> source, TEntity obj, bool isAnd) where TEntity : class
在上文中,我们还碰到了System.Nullable<int>此类类型不支持的问题。其实这个地方主要原因在于我们构造right端的Expression Tree时,没有给它参数。那么这个问题通过Expression right = Expression.Constant(p.GetValue(obj, null), p.PropertyType); 可以得到修复。那整个函数修改后,如下:
public static IQueryable<TEntity> Find<TEntity>(this IQueryable<TEntity> source, TEntity obj, bool isAnd) where TEntity : class
在这里,首先检查输入的参数是否为null。扩展方法其实是按静态方法执行的。它和静态方法唯一不同的就是系统自动为其加了一个Attribute,而这个Attribute只能通过在第一个参数加this关键字才能获得。而后,在影射类型上,修改后的函数只支持数值型和string型。其原因就是像imager等并不支持条件查询。为了简化,我们只支持数值型和string型。这里最大的变化莫过于支持or条件了。调用Expression.And或Expression.Or就可以了。还有一个变化就是ParameterExpression对象和Expression<Func<TEntity, bool>>被移出了foreach循环。这样,提高了效率,只是在最后才去生成条件。
而实际上,大家大多使用是and条件,那再重载一个方法。
public static IQueryable<TEntity> Find<TEntity>(this IQueryable<TEntity> source, TEntity obj) where TEntity : class
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].[City] = @p0) AND ([t0].[Country] = @p1)
-- @p0: Input NVarChar (Size = 6; Prec = 0; Scale = 0) [London]
-- @p1: Input NVarChar (Size = 2; Prec = 0; Scale = 0) [UK]
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].[City] = @p0) OR ([t0].[Country] = @p1)
ORDER BY [t0].[Country]
-- @p0: Input NVarChar (Size = 6; Prec = 0; Scale = 0) [London]
-- @p1: Input NVarChar (Size = 2; Prec = 0; Scale = 0) [UK]
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].[City] = @p0) AND ([t0].[Country] = @p1)
ORDER BY [t0].[CustomerID]
-- @p0: Input NVarChar (Size = 6; Prec = 0; Scale = 0) [London]
-- @p1: Input NVarChar (Size = 2; Prec = 0; Scale = 0) [UK]
2,限定字段在某集合中
这有点像in操作。比如where city in ('London', 'BeiJing') 也可以写成 where city = 'London' or city = 'BeiJing'。既然谈到or条件的动态构造了,那就也来构造下这个吧。看上去有点多此一举。但是,至少是个很好的学习机会。这个和上面不同的是,它条件字段是唯一的,变化的是该字段的值。那用一string将字段名成传入,并用一集合将字段值传入函数。
该函数完整的定义入下:
public static IQueryable<TEntity> WhereOr<TEntity, OrType>(this IQueryable<TEntity> source, string propertyName, IEnumerable<OrType> values)
SELECT [t0].[EmployeeID], [t0].[LastName], [t0].[FirstName], [t0].[Title], [t0].
[TitleOfCourtesy], [t0].[BirthDate], [t0].[HireDate], [t0].[Address], [t0].[City
], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[HomePhone], [t0].[Ext
ension], [t0].[Photo], [t0].[Notes], [t0].[ReportsTo], [t0].[PhotoPath]
FROM [dbo].[Employees] AS [t0]
WHERE [t0].[Region] IS NULL
Linq To Sql是通过Ado.Net于Sql打交道的。也就是说Linq To Sql是建立在CLR基础上的。这点细小的差别让Linq To Sql不知道该与谁保持平行。 Where条件中,有 == 和Equal两个方法,它们在Linq To Sql中是不一样的。Equal认为null是相等的。但是sql又不能用=来判断,所以Equal方法翻译的sql语句就有些长。请大家自己仔细比较下面两个语句的sql差别
var q5 = (from e in db.Employees
from o in db.Orders
where e.Region == o.ShipRegion
select new { e.Region, o }).ToList();
var q6 = (from e in db.Employees
from o in db.Orders
where Equals(e.Region, o.ShipRegion)
select new { e.Region, o }).ToList();
CLR和SQL在数值精度上的差别,也常让CLR抛OverFlow异常.这个很好判断,如果Ado.Net抛这个异常了,那Linq To Sql肯定要抛,所以并不是Linq To Sql的问题。
本文所提到代码,请到此下载完整版本.
相关文章:
C# 3.0 入门系列(一)
C# 3.0入门系列(二)
C# 3.0入门系列(三)
C# 3.0入门系列(四)-之Select操作
C#3.0入门系列(五)-之Where操作
C#3.0入门系列(六)-之OrderBy操作
C#3.0入门系列(七)--之OR工具介绍
C#3.0入门系列(八)-之GroupBy操作
C#3.0入门系列(九)-之GroupBy操作
C#3.0入门系列(十)-之Join操作
C#3.0入门系列(十一)-之In, Like操作
C#3.0入门系列(十二)-Lambda表达式中Lifting
C# 3.0与Linq To Sql的学习方法--浅谈
Linq To Sql进阶系列(一)-从映射讲起
Linq To Sql进阶系列(二)M:M关系
Linq To Sql进阶系列(三)CUD和Log
Linq To Sql进阶系列(四)User Define Function篇
Linq To Sql进阶系列(五)Store Procedure篇
Linq To Sql进阶系列(六)用object的动态查询与保存log篇
TrackBack:http://www.cnblogs.com/126/archive/2007/09/23/902920.html
相关文章推荐
- Linq To Sql进阶系列(七)动态查询续及CLR与SQL在某些细节上的差别
- Linq To Sql进阶系列(七)动态查询续及CLR与SQL在某些细节上的差别
- [转]Linq To Sql进阶系列(七)动态查询续及CLR与SQL在某些细节上的差别
- Linq To Sql进阶系列(七)动态查询续及CLR与SQL在某些细节上的差别
- C# 3.0 介绍(七) - 动态查询续及CLR与SQL在某些细节上的差别
- Linq To Sql进阶系列(六)用object的动态查询与保存log篇
- Linq To Sql进阶系列(六)用object的动态查询与保存log篇
- [转]Linq To Sql进阶系列(六)用object的动态查询与保存log篇
- Linq To Sql进阶系列(六)用object的动态查询与保存log篇
- SQL查询相关技术-1.连接动态字符串
- Linq to sql 实现多条件的动态查询(方法一)
- SQL 查询中动态使用列名(和循环)
- 【sql server inject】使用动态查询执行sql语句实例
- Linq to SQL Dynamic 动态查询
- 利用临时表、REF游标、动态SQL实现分页查询
- 数据库系列之T-SQL(存储过程实现分页查询)
- Mybatis分页查询与动态SQL
- 查询系列当前值的sql语句
- 在sql中查询表中除了某些列之外的列的信息
- 使用存储过程查询数据库(sql有动态拼接)