繁体   English   中英

Linqkit中具有PredicateBuilder的通用查询

[英]Generic Query With PredicateBuilder in Linqkit

我一直在使用LinqKit创建通用查询已有一段时间了。

一直困扰着我的一件事是,您始终必须测试过滤器中发送的值是否有效。

例如:假设我有一个字符串过滤器。 条件可以是Equal,StartsWith,EndsWith和Contains。

我的方法如下所示:

public List<MyModel> Get(MyModelFilter filter)
{
    if (string.IsNullOrEmpty(filter.prop))
    {
        predicate = predicate.And(_myModel => myModel.Prop.Contains(filter.prop));
    }

    // Plus a giant amount of if's with multiple filters

    return DbSet.AsExpandable()
            .Where(predicate)
            .ToList();
}

为了结束这一系列的If,我决定创建一个通用方法来将过滤器应用于属性。 我的想法是传递将应用过滤器的属性和过滤器定义,并封装表达式创建逻辑

它将是以下类型:

public List<MyModel> Get(MyModelFilter filter)
{
    predicate = predicate.And(_myModel => myModel.Prop, filter.PropFilterDefinition);

    // Goodnye If's, Only others filter impl

    return DbSet.AsExpandable()
            .Where(predicate)
            .ToList();
}

为此,我创建了一些扩展方法来处理此问题

public static Expression<Func<TPredicate, bool>> And<TPredicate>(
    this ExpressionStarter<TPredicate> predicate,
    Func<TPredicate, string> property, StringFilterDefinition filter,
    bool ignoreNull = true)
{
    if (InvalidStringFilter(filter, ignoreNull))
    {
        return predicate;
    }

    // This is LinqKit's And Extension Method
    return predicate.And(BuildPredicate(property, filter));
}

private static Expression<Func<TPredicate, bool>> BuildPredicate<TPredicate>(
    Func<TPredicate, string> property,
    StringFilterDefinition filter)
{
    if (filter.Filter == StringFilterComparators.Equal)
    {
        return x => property.Invoke(x) == filter.Value;
    }

    if (filter.Filter == StringFilterComparators.BeginsWith)
    {
        return x => property.Invoke(x).StartsWith(filter.Value);
    }

    if (filter.Filter == StringFilterComparators.EndsWith)
    {
        return x => property.Invoke(x).EndsWith(filter.Value);
    }

    return x => property.Invoke(x).Contains(filter.Value);
}

private static bool InvalidStringFilter(
    StringFilterDefinition filter, 
    bool ignoreNullValue = true)
{
    if (filter?.Filter == null)
    {
        return true;
    }

    return ignoreNullValue && string.IsNullOrEmpty(filter.Value);
}

问题是没有应用过滤器,答案就在上面的Invoke中。 EF无法将上述表达式转换为SQL。 EF错误是

Microsoft.EntityFrameworkCore.Query.Internal.SqlServerQueryCompilationContextFactory [8]无法翻译LINQ表达式'(__property_0.Invoke([x])== __filter_Value_1)',并将在本地对其进行评估。 要配置此警告,请使用DbContextOptionsBuilder.ConfigureWarnings API(事件ID为'RelationalEventId.QueryClientEvaluationWarning')。 重写DbContext.OnConfiguring方法或在应用程序服务提供程序上使用AddDbContext时,可以使用ConfigureWarnings。

问题是:

我该如何进行这项施工? 此外,关于如何做到最好的任何建议?

您似乎忘记了,除了PredicateBuilder之外,LINQKit AsExpandableExpandInvoke自定义扩展方法提供的真正有用的功能是能够正确地将表达式嵌入表达式树中。

为了利用该功能,您应该使用Expression<Func<...>>而不是Func<...> 在发布的代码中,将所有出现的Func<TPredicate, string>替换为Expression<Func<TPredicate, string>> ,此问题应得到解决。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM