2009-05-27 67 views
4

我有下面的代碼位:如何從實體框架導航屬性創建LINQ表達式?

Expression<Func<Subscription, Service>> service2= subscription => (from relationship in subscription.ChildRelationships 
    select relationship.SecondService).FirstOrDefault(); 

它創建以後可以使用作爲與所述實體框架查詢的一部分的表達式。我使用的實際代碼有一個where子句,但爲了便於閱讀,我省略了它。這工作正常,我可以在我用於測試的LINQPad中運行它。

如果我改變代碼:

Expression<Func<Subscription, IQueryable<Service>>> service2= subscription => (from relationship in subscription.ChildRelationships 
    select relationship.SecondService); 

它不再編譯,並具有以下錯誤:

Cannot convert lambda expression to delegate type 'System.Func<Farmworks.Data.Subscription,System.Linq.IQueryable<Farmworks.Data.Service>>' because some of the return types in the block are not implicitly convertible to the delegate return type

這似乎是因爲ChildRelationships這是一個導航屬性未實現IQueryable的。它實際上是EntityCollection類型的,它實現了IEnumerable,但對於創建與EF一起工作的表達式來說並不合適。

我想我明白爲什麼第二塊代碼不起作用,並想知道如何重寫它,以便它可以。還有一個令我感到困惑的是爲什麼第一塊代碼確實有效。它還使用ChildRelationships導航屬性,但沒有任何問題成爲可與EF一起使用的表達式。

任何人都可以擺脫任何光線?

回答

0

我認爲CompiledQuery類可以幫助你在這種情況下:

Expression<Func<Subscription, IQueryable<Service>>> service2 = 
    CompiledQuery.Compile( 
     subscription => (
      from relationship in subscription.ChildRelationships 
      select relationship.SecondService 
     ) 
    ); 
1

的問題不在於FirstOrDefault不知何故使得表達工作;就像你說的那樣,ChildRelationships本身並不實現IQueryable。您可以通過兩種不同的方式解決這個問題,具體取決於您的需求。

您可以使用IEnumerable.AsQueryable方法。如果服務已經從上下文加載,這可能是最好的。

如果服務未加載,您可以根據需要使用加載或包含方法在適當的時間加載它們,然後使用上述解決方案。

如果你有你的ObjectContext的一個參考,你可以使用的ObjectQuery,它確實實現IQueryable的:

Expression<Func<Subscription, MyEntities, IQueryable<Service>>> service2 = 
    (subscription, context) => (
    from s in context.Subscriptions // here is the IQueryable 
    where s.Id == subscription.Id 
    from relationship in s.ChildRelationships 
    select relationship.SecondService); 
+0

嘗試了代碼,但得到了以下結果: 在源類型爲「System.Data.Objects.DataClasses.EntityCollection 」。在對「SelectMany」的調用中,類型推斷失敗。 – GiddyUpHorsey 2009-05-28 21:54:50

0

你需要它的IQueryable <服務>?我認爲select正在返回IEnumerable < Service>。 LINQ直接在IEnumerables上運行,因此您可以將service2聲明爲表達式< Func <訂閱,IEnumerable <服務>>>。