LINQ to Entities 및 LinqKit/PredicateBuilder를 사용하여 리팩터링할 수 없습니다.
문제
저는 LINQ 표현식을 메서드로 리팩터링하려고 노력해 왔으며 "Internal .NET Framework Data Provider error 1025.
" 그리고 "The parameter 'xyz' was not bound in the specified LINQ to Entities query expression.
" 예외.
엔터티 모델의 관련 부분은 다음과 같습니다(EF 4.2/LINQ to Entities 사용).
public class Place : Entity
{
public string OfficialName { get; protected internal set; }
public virtual ICollection<PlaceName> { get; protected internal set; }
}
public class PlaceName : Entity
{
public string Text { get; protected internal set; }
public string AsciiEquivalent { get; protected internal set; }
public virtual Language TranslationTo { get; protected internal set; }
}
public class Language : Entity
{
public string TwoLetterIsoCode { get; protected internal set; }
}
기본적인 관계형 모델은 다음과 같습니다.
Place (1) <-----> (0..*) PlaceName (0..*) <-----> (0..1) Language
검색이 제공되면 해당 쿼리를 작성하려고 합니다. term
, 찾아보세요 Place
그 실체 OfficialName
로 시작합니다 term
또는 PlaceName
누구의 Text
또는 AsciiEquivalent
검색으로 시작됩니다 term
. (Language
쿼리의 일부이긴 하지만 문제가 있는 부분은 아닙니다. PlaceName
s는 다음에 대해서만 일치해야 합니다. CultureInfo.CurrentUICulture.TwoLetterIsoLanguageName
.)
다음 코드 작동합니까:
internal static IQueryable<Place> WithName(this IQueryable<Place> queryable,
string term)
{
var matchesName = OfficialNameMatches(term)
.Or(NonOfficialNameMatches(term));
return queryable.AsExpandable().Where(matchesName);
}
private static Expression<Func<Place, bool>> OfficialNameMatches(string term)
{
return place => place.OfficialName.StartsWith(term);
}
private static Expression<Func<Place, bool>> NonOfficialNameMatches(string term)
{
var currentLanguage = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName;
return place => place.Names.Any(
name =>
name.TranslationToLanguage != null
&&
name.TranslationToLanguage.TwoLetterIsoCode == currentLanguage
&&
(
name.Text.StartsWith(term)
||
(
name.AsciiEquivalent != null
&&
name.AsciiEquivalent.StartsWith(term)
)
)
);
}
내가 다음에 하려는 일은 NonOfficialNameMatches
추출하는 방법 name => ...
다른 쿼리에서 재사용할 수 있도록 표현식을 별도의 메서드로 변환합니다.다음은 제가 시도한 한 가지 예입니다. 작동하지 않습니다 예외가 발생합니다."The parameter 'place' was not bound in the specified LINQ to Entities query expression.
":
private static Expression<Func<Place, bool>> NonOfficialNameMatches(string term)
{
return place => place.Names.AsQueryable().AsExpandable()
.Any(PlaceNameMatches(term));
}
public static Expression<Func<PlaceName, bool>> PlaceNameMatches(string term)
{
var currentLanguage = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName;
return name =>
name.TranslationToLanguage != null
&&
name.TranslationToLanguage.TwoLetterIsoCode == currentLanguage
&&
(
name.Text.StartsWith(term)
||
(
name.AsciiEquivalent != null
&&
name.AsciiEquivalent.StartsWith(term)
)
);
}
내가 가지고 있지 않을 때 .AsExpandable()
체인 연결 NonOfficialNameMatches
, 그러면 "Internal .NET Framework Data Provider error 1025.
" 예외.
나는 팔로우했다 여기에 다른 조언 여러 가지 호출 조합과 같은 .Expand()
그러나 항상 앞서 언급한 예외 중 하나로 끝납니다.
LinqKit/PredicateBuilder와 함께 LINQ to Entities를 사용하여 이 표현식을 별도의 메서드로 분리하는 것이 가능합니까? 그렇다면 어떻게?내가 도대체 뭘 잘못하고있는 겁니까?
해결책
아래 방법이 작동합니다.
private static Expression<Func<Place, bool>> NonOfficialNameMatches(string term)
{
Expression<Func<PlaceName, bool>> placeNameExpr = PlaceNameMatches(term);
Expression<Func<Place, bool>> placeExpr =
place => place.Names.Any(name => placeNameExpr.Invoke(name));
return placeExpr.Expand();
}
편집하다:추가 설명 추가
그만큼 PlaceNameMatches
방법은 작성한 대로 작동합니다.문제는 방법을 사용하는 방법에 있었습니다.표현식의 일부를 제외하려면 위 방법에서 수행한 3단계를 따르세요.
메소드에 의해 생성된 표현식에 지역 변수를 설정합니다.
다른 지역 변수를 지역 변수 표현식을 호출하는 새 표현식으로 설정합니다.
LinkKit 호출
Expand
방법:이렇게 하면 호출된 표현식이 확장됩니다.