我们再来测试一下
Northwind db = new Northwind(); db.Log = Console.Out; Customer cu = new Customer { City = "London", Country = "UK" }; var q0 = db.Customers.Find(cu).ToList(); var q1 = db.Customers.OrderBy(c=>c.Country).Find(cu, false).ToList(); var q2 = Extension.Find(db.Customers.OrderBy(c => c.CustomerID), cu).ToList();
大家可以看到,它们和系统定义方法一样使用,可以接在任何满足条件的语句后面。第三个例子直接就用的static方法的形式。从第三个例子,我们可以看出,extension methods和static methods差别其实不大。
它们生成的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].[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) { if (source == null) throw new ArgumentNullException("Source can't be null!!"); ParameterExpression param = Expression.Parameter(typeof(TEntity), "p"); Expression left = Expression.Property(param, propertyName); Expression condition = null; foreach (OrType value in values) { Expression filter = Expression.Equal(left, Expression.Constant(value)); if (condition == null) condition = filter; else condition = Expression.Or(condition,filter); } if (condition != null) return source.Where((Expression<Func<TEntity, bool>>)Expression.Lambda(condition, param)); return source; }
使用时,
var q3 = db.Customers.WhereOr("City", new List<string> { "London", "BeiJing" }).ToList();
并不在多做解释。
3, CLR与SQL在某些细节上的差别
在上文中,有一朋友提出,其值不为null才做为条件,让函数有局限性。既然提了,那笔者就再引申下。CLR与SQL中,对待null值是不同的。CLR认为两个null值是相等的,而SQL并不这么认为。比如,下面的条件就是成立的。
if (null == null)
throw new Exception("CLR treat Null is the same!!");
但在Sql中只能判断是不是null值,而不能对两个字段的null值直接比较。
比如下面的语句
var q6 = db.Employees.Where(c => c.Region == null).ToList();
翻译为:
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的问题。
文章来源于领测软件测试网 https://www.ltesting.net/