2012-05-16 32 views
6

我在LINQ到實體以下查詢:LINQ到實體不支持調用

var query = from p in db.Products 
      where p.Price > 10M 
      select p; 

此時查詢還沒有執行,我想編寫一個查詢將返回真/假基於在一些條件下:

return query.Any(p => p.IsInStock && 
       (p.Category == "Beverage" || 
       p.Category == "Other")); 

這工作正常;但是,我想從我的代碼中獲得一些重用。我需要根據如果類別是飲料或其他過濾方法很多,所以我試圖創建一個委託:

Func<Product, bool> eligibleForDiscount = (product) => product.Category == "Beverage" || product.Category == "Other"; 

我想替代與委託的線上單向:

return query.Any(p => p.IsInStock && eligibleForDiscount(p)); 

這給了我一個錯誤,說LINQ to Entities不支持Invoke。爲什麼我不能用內聯代碼替代這樣的委託,並且有什麼方法可以通過其他方式實現我的重用?

+1

可能重複://計算器。com/questions/8741667/the-linq-expression-node-type-in​​voke-is-not-supported-in-linq-to-entities-in-e) –

+2

考慮到這個問題沒有被接受的答案,我沒有了解這個PredicateBuilder是什麼,我不認爲這個問題是重複的。 – Dismissile

回答

6

回想一下,引擎蓋Linq-to-{DATABASE}只是將您製作的IQueryable轉換爲Sql。

你可以像不是內嵌代碼,因爲Invoke沒有一致的方式將其改造成一個SQL語句(當你調用一個FuncAction你實際上是調用方法)(你可以做任何事情在那裏)。

也就是說,你可以通過拆分它重用部分:

var query = from p in db.Products 
      where p.Price > 10M 
      select p; 

query = query.Where(p => p.IsInStock); 
query = query.Where(p => p.Category == "Beverage" || p.Category == "Other"); 
return query.Any(); 

這些都可以放入該採取IQueryable<Product>方法和返回相同的(但過濾)。那麼你可以重複使用你的心臟的內容!

+0

所以你的建議是有一個方法,需要IQueryable 並返回IQueryable 而不是委託。我猜他們都做同樣的事情:) – Dismissile

+0

他們做的事情完全一樣,而且它更加可重用......帶IQueryable並返回IQueryable的方法和函數非常強大。 – Crisfole

+1

作爲額外的好處,這也可以作爲一種擴展方法,爲IQueryable接口提供自定義的漂亮的查詢.WhereIsInAnyCategory(「Beverage」,「Other」)(或query.WhereBeverageOrOther())類型的語法。 – MerickOWA

2

問題是,IQueryable需要生成一個SQL表達式傳遞給RDBMS,並且它只有一個不透明的謂詞時才能完成。

顯而易見的,但效率不高的方式是重寫查詢如下:

return query.Where(p => p.IsInStock).AsEnumerable().Any(eligibleForDiscount); 

一個沒有價值的方法是如下:

bool GotEligible(Expression<Func<Product,bool>> pred) { 
    return query.Where(p => p.IsInStock).Any(pred); 
} 

注意此方法的一個謂語,而不是需要謂詞表達式。現在它對EF來說是透明的,並且可以毫無問題地轉換爲SQL查詢。

+0

btw,你想擺脫'Any條款中的'(p)' – Crisfole

+0

@ChristopherPfohl是的,你是對的!謝謝! – dasblinkenlight

+0

* *可能*你的意思是'GotEligible';) – Crisfole

0

只要你堅持使用IQueryable的,你可以保持可重複使用的querys函數。

public IQueryable<Product> EligibleForDiscount(IQueryable<Product> products) 
    { 
     return products.Where(p => product.Category == "Beverage" || 
            product.Category == "Other"); 
    } 

立即調用它的任何其它功能:

IQueryable<Product> query = (from p in db.Products 
           where p.Price > 10M 
           select p); 

    query = EligibleForDiscount(query); 
[該LINQ表達式節點類型「調用」不LINQ支撐以在實體框架實體(HTTP的