实体框架 - "全部"方法

Gus*_*nti 8 linq linq-to-entities entity-framework

所有的方法应该评估对列表中的所有元素的说法.它在常规Linq中运行正常,但是当我尝试将它与EF一起使用时,它会抛出一个错误(" 无法创建类型为'闭包类型'的常量值.此处仅支持基本类型(例如Int32,String和Guid)上下文. ")

例:

var myList = from person in entities.People
             where searchList.All(arg => arg == arg).ToList();
Run Code Online (Sandbox Code Playgroud)

(arg == arg这里只是为了说明我的问题)

在我的场景中,searchList是包含搜索项的列表,例如"John","Accounting","75".在我的EF查询中,我想检索人员中的所有记录,其中John,Accounting和75出现在某些指定的可搜索字段中.一个更现实的例子是这样的:

where SearchList.All((person.FirstName + " " + person.LastName + " " + person.DepartmentName + " " + person.Phone).Contains)
Run Code Online (Sandbox Code Playgroud)

第二个例子在内存中也适用于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;
Run Code Online (Sandbox Code Playgroud)

Dan*_*ner 14

实体框架不支持所有查询.如果您想到以下内容,这一点就变得很明显了

dataContext.Persons.Where(person => MyMethod(person));
Run Code Online (Sandbox Code Playgroud)

MyMethod()返回一个布尔值.该方法可能会执行所有操作,您无法将所有内容转换为SQL.解决方案是ToList()使用LINQ to Object 将所有实体放入本地内存.

dataContext.Persons.ToList().Where(person => MyMethod(person));
Run Code Online (Sandbox Code Playgroud)

它取决于您的实际查询是否可以重写,以便它可以由实体框架转换为SQL,或者如果您必须使用LINQ to Object在本地内存中进行查询.

您提到的例外情况听起来像是在尝试以下内容.

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

dataContext.Employees.Where(employee => employee.Company == company);
Run Code Online (Sandbox Code Playgroud)

LINQ to Entity不支持包含实体的表达式,因此实体的比较Company无效.在这种情况下,您可以按如下方式重写它.

dataContext.Employees.Where(employee => employee.Company.Id == company.Id);
Run Code Online (Sandbox Code Playgroud)

这只比较了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));
}
Run Code Online (Sandbox Code Playgroud)

这将逐字构造查询.注意到实体框架识别ToUpper(),ToLower()Contains()(以及更多) - 所以当我说实体框架不识别方法调用时我是严格的.确实如此,但不是很多,不ToUpperInvariant()ToLowerInvariant().此外,此查询CHARINDEX()使用列的排序规则转换为函数调用,因此搜索可以不区分大小写而不显式ToUpper()ToLower()调用.