Entity Framework- " 'Closure type'유형의 상수 값을 만들 수 없습니다…"오류


79

오류가 발생하는 이유 :

'Closure type'유형의 상수 값을 만들 수 없습니다. 이 컨텍스트에서는 기본 형식 (예 : Int32, String 및 Guid) 만 지원됩니다.

다음 Linq 쿼리를 열거하려고 할 때?

IEnumerable<string> searchList = GetSearchList();
using (HREntities entities = new HREntities())
{
   var myList = from person in entities.vSearchPeople
   where upperSearchList.All( (person.FirstName + person.LastName) .Contains).ToList();
}

업데이트 : 문제를 분리하기 위해 다음을 시도하면 동일한 오류가 발생합니다.

where upperSearchList.All(arg => arg == arg) 

그래서 문제는 All 메서드에있는 것 같습니다. 맞죠? 어떤 제안?

답변:


68

"WHERE ... IN"조건에 해당하는 작업을 수행하려는 것 같습니다. LINQ to Entities사용하여 이러한 유형의 쿼리를 수행하는 방법에 대한 예제는 LINQ to Entities사용하여 'WHERE IN'스타일 쿼리를 작성하는 방법을 확인하세요 .

또한 .Contains괄호가 뒤에 나오지 않아 컴파일러가 전체 술어를 람다 식으로 인식 하게되므로이 경우 오류 메시지가 특히 유용 하지 않다고 생각합니다 .


고마워 다니엘. 동일한 구문이 일반 Linq에서도 잘 작동합니다. 따라서 .Net 3.5 SP1의 EF에 문제가있는 것 같습니다. 괄호가없는 포함은 다음과 동일합니다. 여기서 upperSearchList.All (x => (person.FirstName + person.LastName) .Contains (x)). ToList ();
Gus Cavalcanti

upperSearchList.All (arg => arg == arg) 어디에서 시도하면 동일한 오류가 발생합니다. 그래서 문제는 All 방법에 있습니다 ...
Gus Cavalcanti

2
LINQ to Entities는 훌륭한 기술이지만 SQL 번역 엔진은 제한적입니다. 공식 문서에 손을 넣을 수는 없지만 경험상 쿼리에 기본 수학 및 문자열 / 날짜 함수 이상이 포함되어 있으면 작동하지 않습니다. 내가 링크 한 게시물을 확인할 기회가 있었습니까? "WHERE..IN"유형 쿼리를 LINQ to Entities가 SQL로 변환 할 수있는 형식으로 변환하는 프로세스를 설명합니다.
Daniel Pratt

linq에서 엔티티에 대한 함수 포인터를 사용할 수 없습니다. 공급자는 표현식 트리에서이를 SQL로 변환하는 방법을 모릅니다.
Sinaesthetic apr

@DanielPratt 귀하의 링크가 깨진

11

저는 지난 6 개월 동안 EF 3.5로이 제한과 싸우며 보냈고 제가 세상에서 가장 똑똑한 사람은 아니지만이 주제에 대해 유용한 정보를 제공 할 것이라고 확신합니다.

50 마일 높이의 "OR 스타일"식 트리를 늘려서 생성 된 SQL은 쿼리 실행 계획이 좋지 않습니다. 나는 수백만 개의 행을 다루고 있으며 그 영향은 상당합니다.

ID로 많은 엔티티를 찾는 경우 도움이되는 SQL 'in'을 수행하는 약간의 해킹이 있습니다.

private IEnumerable<Entity1> getByIds(IEnumerable<int> ids)
{
    string idList = string.Join(",", ids.ToList().ConvertAll<string>(id => id.ToString()).ToArray());
    return dbContext.Entity1.Where("it.pkIDColumn IN {" + idList + "}");
}

여기서 pkIDColumn은 Entity1 테이블의 기본 키 ID 열 이름입니다.

그러나 계속 읽으십시오!

이것은 괜찮지 만 내가 찾아야 할 ID가 이미 있어야합니다. 때로는 내 표현이 다른 관계에 도달하기를 원하며 내가 가진 것은 연결된 관계의 기준입니다.

시간이 더 있다면 이것을 시각적으로 표현하려고하지만 잠시만이 문장을 공부하지 않습니다. Person, GovernmentId 및 GovernmentIdType 테이블이있는 스키마를 고려하십시오. Andrew Tappert (Person)에는 두 개의 ID 카드 (GovernmentId)가 있는데, 하나는 Oregon (GovernmentIdType)이고 다른 하나는 Washington (GovernmentIdType)입니다.

이제 그것으로부터 edmx를 생성하십시오.

이제 특정 ID 값 (예 : 1234567)을 가진 모든 사람을 찾고 싶다고 상상해보십시오.

이것은 다음과 같이 단일 데이터베이스 적중으로 수행 할 수 있습니다.

dbContext context = new dbContext();
string idValue = "1234567";
Expression<Func<Person,bool>> expr =
    person => person.GovernmentID.Any(gid => gid.gi_value.Contains(idValue));

IEnumerable<Person> people = context.Person.AsQueryable().Where(expr);

여기에 하위 쿼리가 표시됩니까? 생성 된 SQL은 하위 쿼리 대신 '조인'을 사용하지만 효과는 동일합니다. 요즘 SQL 서버는 어쨌든 커버 아래에서 조인으로 하위 쿼리를 최적화하지만 어쨌든 ...

이 작업의 핵심은 표현식 내부의 .Any입니다.


8

오류의 원인을 찾았습니다 (Framework 4.5를 사용하고 있습니다). 문제는 "Contains"매개 변수로 전달되는 복합 유형 인 EF가 SQL 쿼리로 변환 할 수 없다는 것입니다. EF는 SQL 쿼리에서 int, string ...과 같은 단순한 유형 만 사용할 수 있습니다.

this.GetAll().Where(p => !assignedFunctions.Contains(p))

GetAll은 복합 유형 (예 : "함수")의 개체 목록을 제공합니다. 따라서 여기에서 SQL 쿼리에서이 복잡한 유형의 인스턴스를 수신하려고합니다.이 인스턴스는 자연스럽게 작동하지 않습니다!

내 목록에서 내 검색에 적합한 매개 변수를 추출 할 수 있다면 다음을 사용할 수 있습니다.

var idList = assignedFunctions.Select(f => f.FunctionId);
this.GetAll().Where(p => !idList.Contains(p.FunktionId))

이제 EF는 더 이상 작동 할 복잡한 유형 "함수"를 갖지 않지만 예를 들어 단순 유형 (long)을 사용합니다. 그리고 그것은 잘 작동합니다!


0

.All 함수에 사용 된 배열 개체가 null 인 경우이 오류 메시지가 나타납니다. 배열 개체 (귀하의 경우 upperSearchList)를 초기화 한 후 오류가 사라졌습니다.이 경우 오류 메시지가 잘못되었습니다.

여기서 upperSearchList.All (arg => person.someproperty.StartsWith (arg)))

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.