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

时间:2014-02-23 13:59:13

标签: c# 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);
}

我只是想知道为什么另一个有效,但另一个没有。

对示例的一个很好的解释可能有所帮助。感谢

4 个答案:

答案 0 :(得分:26)

第一种情况不起作用的原因是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); 
}

情景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); 
}

答案 1 :(得分:8)

使用var时,编译器会在赋值右侧推断出表达式的类型。当你写

var query = _db.Products;

query属于DbSet<Product>类型,无法分配任何IQueryable<Product> Where扩展方法返回的内容。

当您使用查询语法时,query再次成为IQueryable<Product>,这使其有效。这相当于写作

var query = products.Select(t => t);

Select扩展方法,如Where,返回IQueryable<Product>

答案 2 :(得分:0)

这是因为_db.Products不是查询,而是DbSet。

第二个块可以工作,因为你将它转换为IQueryable,最后一个块可以工作,因为它是一个实际的查询。

答案 3 :(得分:0)

var query = _db.Products.Where(x => true);
if (bool) {
  query = query.Where(p => p.Id == id);
}