2017-12-05 20 views
0

EnitityFramework 6을 사용하여 입력 유형 (데이터베이스 엔터티)이 IQueryable이고 출력 유형이 IQueryable 인 메서드를 만듭니다. 변환기 클래스에는 입력 유형의 단일 인스턴스를 출력 유형의 단일 인스턴스로 변환하는 메소드도 있습니다. .Select 람다 파라미터의 변환 방법을 사용하여 런타임 예외 발생 :Linq to Entities IQueryable의 엔티티 변환 유형

System.NotSupportedException : 방법 '바 변환 (푸)'방법 및이 방법을 인식하지 않는 엔티티 LINQ는 저장소로 번역 할 수없는 표현.

internal static class FooConverter 
{ 
    internal static IQueryable<Bar> Convert(IQueryable<Foo> foos) 
    { 
     return foos.Select(d => Convert(d)); 
    } 

    internal static Bar Convert(Foo foo) 
    { 
     return new Bar 
     { 
      Id = foo.Id, 
      Number = foo.Number, 
      Valid = foo.Valid ?? false, 
     }; 
    } 
} 

연구는 Linq에 엔티티에 내 Convert(Foo) 방법에서 SQL을 생성 할 수 있음을 시사한다, 그래서 나는 몇 가지 리팩토링을했다. 두 방법 모두에서 초기화를 복제하면 모든 것이 작동합니다.

internal static class FooConverter 
{ 
    internal static IQueryable<Bar> Convert(IQueryable<Foo> foos) 
    { 
     return foos 
      .Select(d => new Bar 
      { 
       Id = foo.Id, 
       Number = foo.Number, 
       Valid = foo.Valid ?? false, 
      )}; 
    } 

    internal static Bar Convert(Foo foo) 
    { 
     return new Bar 
     { 
      Id = foo.Id, 
      Number = foo.Number, 
      Valid = foo.Valid ?? false, 
     }; 
    } 
} 

하지만 이제 코드가 중복되었습니다. 이중화를 제거하기 위해 Convert(IQueryable<Foo>)에서 Convert(Foo)으로 전화 할 수 있습니까?

+2

문제는 표현의 해당 된 IQueryable 거래입니다. 쿼리 공급자는 표현식 트리를 탐색/방문하고 그 방법을 알고있는 모든 것을 SQL로 변환합니다. 그러나 그것은 단지 표면에서 알고있는 것을 번역 할 수 있습니다. 임의의 메서드 호출을 투영에 필요한 NewExpression/MemberInitExpressions으로 변환하는 방법을 이해하지 못합니다. Convert는 표현식을 반환 한 다음 복제하지 않으려면 LINQ가 아닌 메서드에서 사용할 대리자에게 컴파일 및 캐시합니다. – pinkfloydx33

+0

thanks pinkfloyd. 나는 표현식 에 익숙하지 않았지만 귀하의 의견은 올바른 방향으로 나를 이끌었습니다. https://msdn.microsoft.com/en-us/library/bb335710(v=vs.110).aspx – chadnt

답변

0

pinkfloydx33의 크레디트. 그의 코멘트는 나를 Expression<TDelegate> 이끌었다. 다른 사람에게 가치가있을 수 있으므로 여기에 전체 해결책을 게시 할 것입니다.

internal static class FooConverter 
{ 
    internal static Expression<Func<Bar, Foo>> FooToBarExpression = 
     (d) => new Bar 
     { 
      Id = foo.Id, 
      Number = foo.Number, 
      Valid = foo.Valid ?? false, 
     }; 

    internal static IQueryable<Bar> Convert(IQueryable<Foo> foos) 
    { 
     return foos.Select(FooToBarExpression)}; 
    } 

    internal static Bar Convert(Foo foo) 
    { 
     return FooToBarExpression.Compile().Invoke(foo); 
    } 
} 

은 참조 : https://msdn.microsoft.com/en-us/library/bb335710(v=vs.110).aspx

+0

이 경우 AutoMapper를 사용합니다. –

+0

이렇게하면,'Func'타입의 개인 정적 변수를 저장하고'Compile '을 한 번 호출하여 변수에 저장합니다. 그런 다음 Convert 메서드를 대리자를 호출하는 통과 메서드로 사용합니다. 그렇지 않으면 메서드를 호출 할 때마다 식을 컴파일하는 오버 헤드가 있습니다. – pinkfloydx33