[英]Cannot implicitly convert type 'System.Data.Entity.Infrastructure.DbSqlQuery’ to 'System.Linq.IQueryable’
[英]Cannot implicitly convert type 'System.Linq.IQueryable' to 'System.Data.Entity.DbSet'
我是Linq
新手,所以我在下面Linq
这些情况。
现在在编译过程中出现以下错误,表示Cannot implicitly convert type 'System.Linq.IQueryable' to 'System.Data.Entity.DbSet'.
var query = _db.Products;
if (bool) {
query = query.Where(p => p.Id == id);
}
所以我尝试将var
更改为IQueryable
并且它有效。
IQueryable<Product> query = _db.Products;
if (bool) {
query = query.Where(p => p.Id == id);
}
但是后来,我尝试再次更改它(见下文)并且它有效。
var query = from product in products
select product;
if (bool) {
query = query.Where(p => p.Id == id);
}
我只想知道为什么另一个有效,而另一个无效。
一个很好的例子解释可能会有所帮助。 谢谢
第一种情况不起作用的原因是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)
,因为你最终会得到一个混乱的异常,因为query.Where(p => p.Id == id)
的结果实际上不是DbSet<Customer>
的实例,但是而是一些表示在DbSet<Customer>
上执行的查询结果的类,它实现了IQueryable
接口。
所以,总而言之,让我们来看看所有的场景:
场景一:
//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);
}
场景3:
//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)
可能会将WHERE 1=1
添加到您的 SQL 查询中。
使用var
,编译器会推断赋值右侧的表达式类型。 当你写
var query = _db.Products;
query
的类型为DbSet<Product>
,并且不能为其分配任何IQueryable<Product>
,其中扩展方法返回Where
扩展方法。
当您使用查询语法时, query
再次是IQueryable<Product>
,这使它起作用。 相当于写
var query = products.Select(t => t);
Select
扩展方法,如Where
,返回IQueryable<Product>
。
这是因为_db.Products
不是查询,而是 DbSet。
第二个块起作用是因为您将其转换为 IQueryable,而最后一个块起作用是因为它是一个实际查询。
var query = _db.Products.Where(x => true);
if (bool) {
query = query.Where(p => p.Id == id);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.