无法使用 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
方法:这将扩展任何调用的表达式