首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Linqkit中使用PredicateBuilder的通用查询

Linqkit中使用PredicateBuilder的通用查询
EN

Stack Overflow用户
提问于 2017-04-19 18:15:06
回答 1查看 2.5K关注 0票数 1

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

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

例如:假设我有一个字符串过滤器。条件可以是相等的,StartsWith,EndsWith,并包含。

我的方法应该如下所示:

代码语言:javascript
复制
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,我决定创建一个泛型方法来将过滤器应用于属性。我的想法是传递应用筛选器的属性和筛选器定义,并封装表达式创建逻辑。

这将是某种类型的:

代码语言:javascript
复制
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();
}

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

代码语言:javascript
复制
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);
}

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

Microsoft.EntityFrameworkCore.Query.Internal.SqlServerQueryCompilationContextFactory8 LINQ表达式'(__property_0.Invoke(x) == __filter_Value_1)‘无法翻译,将在本地计算。要配置此警告,请使用DbContextOptionsBuilder.ConfigureWarnings API (事件id DbContextOptionsBuilder.ConfigureWarnings)ConfigureWarnings可用于重写DbContext.OnConfiguring方法或在应用程序服务提供程序上使用AddDbContext。

问题是:

我怎样才能把这个建筑做好呢?还有,有什么建议是最好的吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-04-19 18:26:02

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

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

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43503236

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档