第一种情况不起作用的原因是
System.Linq.IQueryable
是一个接口,它被实现在
System.Data.Entity.DbSet
类中。在C#中,如果类
C
实现了接口
I
,在类型之间的转换时,你可以把
I
当作
C
的基类(即使语义上
class C : I
也暗示了这种方法)。由于你不能将类(或接口)隐式地(即不详细说明)转换为它的子类之一,所以当你尝试这样做时会得到一个编译时错误。你可以反过来做,也就是将一个子类隐式转换为它的基类(或接口)。这正是第二种情况发生的情况。
在你的情况下,你可以通过显式转换来欺骗编译器:
query = (DbSet<Customer>) query.Where(p => p.Id == id)
我强烈建议你不要这样做,因为你最终会遇到混乱的异常。原因是
query.Where(p => p.Id == id)
的结果实际上并不是
DbSet<Customer>
的实例,而是一个表示在
DbSet<Customer>
上执行查询的结果的类,该类实现了
IQueryable
接口。
所以,总结一下,让我们回顾一下所有的情况:
情况1:
//query is of type DbSet<Customer>
var query = _db.Products;
if (bool) {
//here you're trying to assign a value of type IQueryable<Customer>
//to a variable of it's descendant type DbSet<Customer>
//hence the compile-time error
query = query.Where(p => p.Id == id);
}
场景2:
//here you implicitly cast value of type DbSet<Customer>
//to IQueryable<Customer>, which is OK
IQueryable<Customer> query = _db.Products;
if (bool) {
//here you're assigning a value of type IQueryable<Customer>
//to a variable of the same type, which is also OK
query = query.Where(p => p.Id == id);
}
场景三:
//I assume you have the following line in your code
var products = _db.Products;
//query is of type IQueryable<Customer>, because you perform
//a query on the DbSet<Product>
var query = from product in products
select product;
if (bool) {
//here you're assigning a value of type IQueryable<Customer>
//to a variable of the same type, which is OK
query = query.Where(p => p.Id == id);
}
编辑
我回答这个问题已经有一段时间了,尽管它的价值依然存在,但我倾向于使用稍微不同的方法(可能在原始答案时还没有可用,我不确定)。
将实现IQueryable<T>
接口的对象转换为IQueryable<T>
最简单(也是我认为最安全)的方法是:
var query = _db.Products.AsQueryable();
这仅仅返回对其
IQueryable<T>
接口实现的调用主题。执行查询时不应产生任何额外开销。现在,有一些评论建议使用一些技巧,我认为使用这些技巧可能是一个坏主意。
其中一个例子就是使用这个:
var queryable = query.Select(x => x)
虽然在查询对象时几乎完全没有副作用,但在处理某些 IQueryable<T>
实现时可能会造成一些危害。例如,当查询被转换为 SQL 查询时,它很可能会向执行的查询中添加一个冗余的 "SELECT * FROM ..."
。这是最好的情况 - 在最有可能的情况下,它将添加更加繁琐的内容,例如 "SELECT x.P1, x.P2, ... FROM ... AS x"
。当然,你可能觉得这没问题,但你应该意识到,根据实现的不同,这样的调用可能并不是“免费”的,尽管看起来什么都没做。
另一个例子:
query.Where(x => true)
这可能会在您的SQL查询中添加一个WHERE 1=1
。
using System.Data.Entity;
。 - Eli Arbelvar query = db.Products.Select(x => x);
解决了它。是的,这对我来说也很奇怪。 - Dimitar Nikovskiquery.AsQueryable().Where(......)
运行良好。 - Rohith K P