我一直在尝试将 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 不是我遇到麻烦的地方,尽管它是查询的一部分,因为 PlaceNames 应该只匹配 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 个步骤操作。

  1. 将局部变量设置为方法创建的表达式。

  2. 将另一个局部变量设置为调用局部变量表达式的新表达式。

  3. 调用LinkKit Expand 方法:这将扩展任何调用的表达式

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top