2014-02-23 60 views
14

我是Linq中的新成員,所以我有下面這些情況。不能將類型'System.Linq.IQueryable'隱式轉換爲'System.Data.Entity.DbSet'

現在下面的錯誤在編譯過程中,說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); 
} 

所以我試圖改變varIQueryable和它的作品。

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

而我只是想知道爲什麼另一個可以工作,但另一個不是。

一個很好的例子說明可能會有所幫助。謝謝

+0

你可能會丟失'使用System.Data.Entity;' –

+0

即使我有那個名字空間,仍然錯誤。但我上面的代碼工作。只是想知道爲什麼。 –

+0

剛纔有同樣的問題,並通過'var query = db.Products.Select(x => x)'等價來解決它;'是的,它對我來說確實也很奇怪。 –

回答

18

第一種情況不起作用的原因是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>的實例,而是代表在實現IQueryable接口的DbSet<Customer>上執行的查詢的結果的一些類。

所以,總結起來,讓我們通過所有的場景:

方案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); 
} 
+0

IQueryable medRef = context.MediaRefs; if(MediaId!= null) medRef = medRef.Where(w => w.MediaId == MediaId); ..但這在我的場景中不起作用..(場景2) – Dragon

+0

@Sadaquat你究竟是什麼意思通過「不工作」?代碼是否不能編譯?如果有的話,錯誤信息是什麼?否則,是否會引發異常,如果是,那麼異常消息是什麼? – Grx70

+0

它給出編譯時錯誤,同樣的錯誤。 儘管我已經完成了使用方案3方法的工作,但不能將類型'System.Linq.IQueryable <>'隱式轉換爲'System.Data.Entity.DbSet <>「,但我很想知道爲什麼場景2給編譯錯誤 – Dragon

0

這是因爲_db.Products不是查詢,它是一個DbSet。

第二個塊的工作原理是將它轉換爲IQueryable,而最後一個塊因爲它是一個實際查詢而起作用。

+0

因此,如果我聲明一個'DbSet'並將其分配給一個通用的。 DbSet被投下了? –

+1

使用'DbSet'的原因很少,特別是在這種情況下。只需查詢數據庫。 – dursk

+0

DbSet 實現IQueryable 所以它是一個查詢。問題不在於'query.Where(...)',而是賦值爲「query = query.Where(...)」。換句話說,問題不在於DbSet不是Query,而是Query不是DbSet。 –

4

使用var時,編譯器會將表達式的類型推斷到賦值的右側。當你寫

var query = _db.Products; 

queryDbSet<Product>型的,它不能被分配任何IQueryable<Product>,其中Where擴展方法返回。

當您使用查詢語法時,query再次是IQueryable<Product>,這使得它工作。這相當於寫作

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

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

相關問題