LINQからエンティティとLINQKIT / PRESICATEBUILDERを使用してリファクタリングできません
質問
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を使用したエンティティを使用):
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
のみに照合する必要があるため、CultureInfo.CurrentUICulture.TwoLetterIsoLanguageName
はQueryの一部です。)
次のコードが働く:
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
メソッドをRefactorにして、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()
のいくつかの組み合わせなど、常に1つになっています。前述の例外の。
この式をLINQKIT / PRESICATEBUILDERを使用してLINQを使用して別の方法にすることもできますか?では、どうやって?私は何を間違っていますか?
解決
以下の方法は機能するべきです:
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
メソッドを呼び出します。これにより、呼び出された式が に展開されます。