一、事件
最近做一項目,要求實現如下查詢:
有三個表:論文(Paper),期刊(Magazine),期刊學科分類(MagazineSubjectClass),三者關系為:論文和期刊的關系為一對多(一篇論文對應一個期刊,一個期刊對應多篇論文),期刊和期刊分類的關系是一對多(一個期刊對應多個分類),如圖:
要求實現的查詢如下:
給出一“學科分類”集合(字符串數組),查詢發表在“學科分類”屬於這個集合中的雜志上的論文。
二、響應事件
我的思路如下:
根據學科分類找出符合條件的雜志
根據雜志找出符合條件的論文
於是,我寫下如下linq語句:
IQueryable<Magazine> magazines = database.Magazines.AsQueryable();
if (paperQueryInformation.MagazineQueryInformation.SubjectClass != null && paperQueryInformation.MagazineQueryInformation.SubjectClass.Length != 0)
{
magazines = database.MagazineSubjectClasses
.Where(q => paperQueryInformation.MagazineQueryInformation.SubjectClass.Contains(q.SubjectClass))
.Select(q => q.Magazine)
.Distinct();
query = query
.Where(q => magazines.Contains(q.Magazine));
}
運行,發生如下錯如:
Queries with local collections are not supported
為什麼出現這個錯誤呢?原來是linq的延遲執行導致了這個錯誤,知道了原因,我改進如下:
IList<Magazine> magazines = database.Magazines.ToList();
if (paperQueryInformation.MagazineQueryInformation.SubjectClass != null && paperQueryInformation.MagazineQueryInformation.SubjectClass.Length != 0)
{
magazines = database.MagazineSubjectClasses
.Where(q => paperQueryInformation.MagazineQueryInformation.SubjectClass.Contains(q.SubjectClass))
.Select(q => q.Magazine)
.Distinct()
.ToList();
query = query
.Where(q => magazines.Contains(q.Magazine));
}
運行,就錯誤沒有了,可是出現了新的錯誤,如下:
Method 'Boolean Contains(Srims.Business.Papers.Magazine)' has no supported translation to SQL
解決這個錯誤的方法就是將將類型轉換為泛型 IEnumerable,使用 AsEnumerable<TSource> 可返回類型化為泛型 IEnumerable 的參數。LINQ to SQL(使用默認泛型 Query)會嘗試將查詢轉換為 SQL 並在服務器上執行。但在有寫情況下,此方法無法轉換為 SQL。解決方法是用泛型 IEnumerable<T> 實現以替換泛型 IQueryable<T>。可通過調用 AsEnumerable<TSource>運算符來執行此操作。
我改進查詢語句如下:
IList<Magazine> magazines = database.Magazines.ToList();
if (paperQueryInformation.MagazineQueryInformation.SubjectClass != null && paperQueryInformation.MagazineQueryInformation.SubjectClass.Length != 0)
{
magazines = database.MagazineSubjectClasses
.Where(q => paperQueryInformation.MagazineQueryInformation.SubjectClass.Contains(q.SubjectClass))
.Select(q => q.Magazine)
.Distinct()
.ToList();
query = query
.Where(q => magazines.AsEnumerable()
.Contains(q.Magazine));
}
運行,結果正確,問題解決。
三、後記
經過不斷的努力,問題終於解決了。在LINQ TO SQL的復雜查詢中,linq的延遲執行和經linq語句翻譯成sql語句的過程中,會發生很錯想不到的錯誤,這是我碰到的最多的一個,今天終於解決了,拿出來和大家分享下,希望能拋磚引玉。^_^