环境
使用MySQL Connector NET 6.7.4+EF5.0+VS2010
问题描述
IQueryable<T>类型的Where方法和Skip或Take方法一起使用时,生成的SQL语句错误。
首先定义一个Model
1 public class User 2 { 3 public string Id { set; get; } 4 public string Name { set; get; } 5 }
运行如下程序,本意是要查询User表中Name包含"Test"的记录,并返回前10条:
1 string Name = "Test"; 2 var Data = db.Set<User>().Where<User>(o => o.Name.Contains(Name)). 3 OrderBy<User,string>(o=>o.Id). 4 Skip<User>(0). 5 Take<User>(10);
运行后抛出"执行命令定义时出错。有关详细信息,请参阅内部异常",调试发现生成的SQL如下:
1 SELECT 2 `Project1`.`Id`, 3 `Project1`.`Name` 4 FROM `User` AS `Project1` 5 WHERE (LOCATE(@p__linq__0, `Extent1`.`Name`)) > 0 6 ORDER BY 7 `Project1`.`Id` ASC LIMIT 0,10
原来生成的SQL中根本就没有 Extent1 这个别名,所以查询的时候自然就报错误,将代码修改成这样(即将变量直接换成文字):
1 var Data = db.Set<User>().Where<User>(o => o.Name.Contains("Test")). 2 OrderBy<User,string>(o=>o.Id). 3 Skip<User>(0). 4 Take<User>(10);
生成的SQL为:
1 SELECT 2 `Extent1`.`Id`, 3 `Extent1`.`Name` 4 FROM `User` AS `Extent1` 5 WHERE `Extent1`.`Name` LIKE '%Test%' 6 ORDER BY 7 `Extent1`.`Id` ASC LIMIT 0,10
运行结果正常。
之后将数据源换成SQL Server数据库后 同样的写法也一切正常,不知道这是不是MySql.Data.Entity生成SQL的一个BUG
解决办法
抱着试试的态度,将Where方法放到Take方法后即:
1 string Name = "Test"; 2 var Data = db.Set<User>().OrderBy<User,string>(o=>o.Id).Skip<User>(0).Take<User>(10).Where<User>(o => o.Name.Contains(Name));
生成的SQL为:
1 SELECT 2 `Project1`.`Id`, 3 `Project1`.`Name` 4 FROM (SELECT 5 `Extent1`.`Id`, 6 `Extent1`.`Name` 7 FROM `User` AS `Extent1` 8 WHERE (LOCATE(@p__linq__0, `Extent1`.`Name`)) > 0 9 ORDER BY 10 `Extent1`.`Id` ASC LIMIT 0,10) AS `Project1` 11 ORDER BY 12 `Project1`.`Id` ASC
Ok,运行,正常了。