2012-11-16 107 views
1

我一直在擺弄整整兩天,現在有一個簡單的問題。IQueryable的擴展沒有轉換到SQL

我有一個產品實體和ProductLocationHistory實體的數據庫。 ProductLocationHistory具有對倉庫,聯繫人或關係的引用。每次產品移動時,都會得到一個新條目,以便跟蹤產品的過去。因此,當前位置是由ProductLocationHistory的DateCreation字段確定的最後一個條目。

一個例子:

var storehousesWithBorrowedItems = productService.GetAllProducts() 
    .Select(p => p.ProductLocationHistories 
     .SingleOrDefault(plh => plh.DateCreation == p.ProductLocationHistories.Max(grp => grp.DateCreation))) 
    .Select(plh => plh.Storehouse) 
    .Distinct(); 

這些是目前有一個產品的所有倉庫。

當然,我需要確定產品的當前位置時,將代碼編寫出來非常不方便。由於可能出現的一致性問題,我認爲對產品中當前的ProductLocationHistory的引用完全是不受歡迎的。我喜歡這樣的:

Product.ProductLocationHistories.Current(); 

所以,我想:

public static ProductLocationHistory Current(this EntitySet<ProductLocationHistory> plhs) 
    { 
     return plhs.SingleOrDefault(plh => plh.DateCreation == plhs.Max(grp => grp.DateCreation)); 
    } 

這並不在可查詢的工作,我得到一個「當前沒有支持轉換爲SQL」,由於產品組合而ProductLocationHistory通常是查詢的「開始」,我希望保留IQueryable而不是立即對IEnumerable進行查詢,併爲每個產品查詢以確定當前位置!更別說以後還有其他什麼東西......任何實體的當前日誌條目經常被使用,只要它能夠工作並保持可查詢,.Current()函數的複雜程度就不重要了。我希望我的.Current(...)函數可以工作,因爲底層代碼是可查詢的,但我仍然遇到異常。當代碼與第一個示例中一樣內聯時,我沒有得到異常。

我已經經歷過像Func,ProductLocationHistory >>和表達式< ...>的可能性...>,但是我找不到我正在尋找的示例。類型Product.CurrentProductLocationHistory()的解決方案可能會更好。絕對最好的解決辦法是更通用的形式:

Current<T> (IQueryable<T> collection, string field) { return entity with max field of collection } 

幫助將不勝感激,我一直在嘗試這個很長一段時間,我敢肯定那一定是可能的,因爲內部功能LINQ本身 - 任何,首先,計數,最大 - 如果需要也可以保持查詢。

更新

目前,以下工作:

Expression<Func<Product, ProductLocationHistory>> expression = IQueryable.Current(null); 
     var ken = productService.GetAllProducts() 
      .Where(p => p.OnLoan) 
      .Select(expression) 
      .Where(plh => plh.Storehouse != null) 
      .Select(plh => plh.Storehouse) 
      .Distinct(); 

public static Expression<Func<Product, ProductLocationHistory>> Current(this EntitySet<ProductLocationHistory> productLocationHistories) 
    { 
     Expression<Func<Product, ProductLocationHistory>> expression = p => p.ProductLocationHistories 
             .SingleOrDefault(plh => plh.DateCreation == p.ProductLocationHistories.Max(plhs => plhs.DateCreation)); 
     return expression; 
    } 

朝着正確方向邁出的一步,但我還沒有完全滿意。我希望能夠使用p.ProductLocationHistories()。Current()來繼續我的追求。

感謝Kirill!這是我第一次將C#代碼翻譯成SQL!朝着正確的方向邁出了一步!

+0

有了這個擴展方法,你可以* *調用.Current()如果我不是誤。你可以展示你想使用的調用約定的示例嗎?此外,使用'OrderByDescending(pld => pld.DateCreation).FirstOrDefault()'比使用'SingleOrDefault'查詢max要快很多。 – jessehouwing

+0

我會盡快升級到ASP.NET 4.5,然後嘗試解決方案[link](http://stackoverflow.com/questions/10826275/queryable-extension-method-for-linq2entities)。目前我們正在收購Visual Studio 2012.之後我可能會更新此問題。 – Paul1977

回答

1

您可以設置字段表達式:

Expression<Func<ProductLocationHistory, bool>> currentSelector = plh => plh.DateCreation == p.ProductLocationHistories.Max(grp => grp.DateCreation) 

,並在任何地方使用它:

var storehousesWithBorrowedItems = productService.GetAllProducts() 
    .Select(p => p.ProductLocationHistories 
     .SingleOrDefault(currentSelector)) 
    .Select(plh => plh.Storehouse) 
    .Distinct(); 
+0

如果我幫助 - 接受答案 –

+0

據我記得這個功能,但沒有我想要的那樣可用。 .Current()經常用於日誌,我願意儘可能地解決這個問題。因爲沒有包括編寫自己的可查詢函數的可能性,所以對微軟感到羞愧。我認爲這是相當遺漏的。其餘部分,LINQ使我的生活變得更加簡單,比以前用動態SQL文本字符串* br *更容易。 – Paul1977