實體框架 - “全部”方法

entity-framework linq linq-to-entities

All方法應該針對列表中的所有元素計算參數。它在常規Linq中運行正常,但是當我嘗試將它與EF一起使用時,它會拋出一個錯誤(“ 無法創建類型為'閉包類型'的常量值。此處僅支持基本類型(例如Int32,String和Guid)上下文。 “)

例:

var myList = from person in entities.People
             where searchList.All(arg => arg == arg).ToList();

(arg == arg這裡只是為了說明我的問題)

在我的場景中,searchList是包含搜索項的列表,例如“John”,“Accounting”,“75”。在我的EF查詢中,我想檢索人員中的所有記錄,其中John,Accounting和75出現在某些指定的可搜索字段中。一個更現實的例子是這樣的:

where SearchList.All((person.FirstName + " " + person.LastName + " " + person.DepartmentName + " " + person.Phone).Contains)

第二個例子在內存中也適用於Linq,但EF不喜歡它。

請幫忙!我能做些什麼才能讓它發揮作用?

這是一個來自我的另一個問題的更具體的問題。

示例代碼:

IEnumerable<string> searchList = ParseSearchText(searchText); //search text is broken into search tokens - each token is an element in searchList. For instance "John", "Sales", "654"

var peopleQuery = from person in entities.vSearchPeople
where upperSearchList.All((person.FirstName + " " + person.Lastname + " " + person.Phone).ToUpperInvariant().Contains)
select person;

一般承認的答案

實體框架不支持所有查詢。如果您想到以下內容,這一點就變得很明顯了

dataContext.Persons.Where(person => MyMethod(person));

使用MyMethod()返回一個布爾值。該方法可能會執行所有操作,您無法將所有內容轉換為SQL。解決方案是使用ToList()將所有實體放入本地內存,然後使用LINQ to Object。

dataContext.Persons.ToList().Where(person => MyMethod(person));

它取決於您的實際查詢是否可以重寫,以便它可以由實體框架轉換為SQL,或者如果您必須使用LINQ to Object在本地內存中進行查詢。

您提到的例外情況聽起來像是在嘗試以下內容。

Company company = datacontext.Companies.Where(company.Name == "ACME").Single();

dataContext.Employees.Where(employee => employee.Company == company);

LINQ to Entity不支持包含實體的表達式,因此Company實體的比較無效。在這種情況下,您可以按如下方式重寫它。

dataContext.Employees.Where(employee => employee.Company.Id == company.Id);

這只比較了id - 一個像整數或GUID這樣的基本類型 - 這可以轉換為SQL。

逐字搜索示例(另請參閱註釋)

IQueryable<People> result = entities.People;

foreach (String item in searchList)
{
    // This copy is important in order not to modify the closure.
    String itemCopy = item;

    result = result.Where(p =>
        p.FirstName.ToUpper().Contains(itemCopy) ||
        p.LastName.ToUpper().Contains(itemCopy) ||
        p.Phone.ToUpper().Contains(itemCopy));
}

這將逐字構造查詢。注意到實體框架識別ToUpper()ToLower()Contains() (以及更多) - 所以當我說實體框架不識別方法調用時,我是嚴格的。它確實,但不是很多,而不是ToUpperInvariant()ToLowerInvariant() 。此外,此查詢使用列的排序規則轉換為CHARINDEX()函數調用,因此在沒有顯式ToUpper()ToLower()調用的情況下,搜索可以不區分大小寫。


熱門答案

這個好例子在All()方法中有什麼好處。

model.ReferenceList = db.JournalCardReference.OrderBy(a => a.orderF)
 .Include(x => x.JournalCardField)
  .Where(x => x.JournalCardField
    .All(f => f.deleted == null || f.deleted != true)).ToList();


許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因