繁体   English   中英

无法将类型“System.Linq.IQueryable”隐式转换为“System.Data.Entity.DbSet”

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM