6

我一直在尝试将 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

我正在尝试创建一个查询,当给定 search 时,它将term尝试查找以OR开头的Place实体,其具有who或以 search 开头。(不是我遇到问题的地方,尽管它是查询的一部分,因为s 应该只匹配。)OfficialNametermPlaceNameTextAsciiEquivalenttermLanguagePlaceNameCultureInfo.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 将此表达式分解为单独的方法吗?如果是这样,怎么做?我究竟做错了什么?

4

1 回答 1

7

下面的方法应该有效:

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. 调用 LinkKitExpand方法:这将扩展所有 Invoked 表达式

于 2012-05-29T20:00:12.200 回答