繁体   English   中英

如何创建表达式 <Func<TSource, bool> 通过比较Func <TSource, int> 用int

[英]How to create Expression<Func<TSource, bool> by comparing Func<TSource, int> with int

我有一个带有很多DbSet的DbContext。 每个DbSet都应该有一个函数来获取集合中的一个页面,具有给定的pageSize并由特定的sortOrder排序。 就像是:

var pageItems = dbContext.Posts
    .Where(post => post.BlogId == blogId)
    .OrderBy(some sortorder)
    .Skip(pageNr * pageSize)
    .Take(pageSize);

我希望能够使用我的所有DbSet执行此操作,因此我创建了一个扩展方法,其中一个参数指定要比较的外键,另一个指定该外键应具有的值。

public static IQueryable<TSource> GetPage<TSource>(this IQueryable<TSource> source,
    int pageNr, int pageSize,
    Expression<Func<TSource, Tproperty>> keySelector, Tproperty comparisonValue)
{
    return  source
    .Where( ??? )
    .OrderBy(some sortorder)
    .Skip(pageNr * pageSize)
    .Take(pageSize);
}

如何在适合Where的谓词中转换keySelector?

如何在适合Where的谓词中转换keySelector?

这很容易,但我不知道你将如何处理订购。 无论如何,这是你如何做你要求的:

public static IQueryable<TSource> GetPage<TSource, TKey>(this IQueryable<TSource> source,
    int pageNr, int pageSize,
    Expression<Func<TSource, TKey>> keySelector, TKey comparisonValue)
{
    var predicate = Expression.Lambda<Func<TSource, bool>>(
        Expression.Equal(keySelector.Body, Expression.Constant(comparisonValue)),
        keySelector.Parameters);

    return source
        .Where(predicate)
        //.OrderBy(some sortorder) ??
        .Skip(pageNr * pageSize)
        .Take(pageSize);
}

您正在寻找一种从Expression<Func<TSource, Tproperty>> keySelectorTproperty comparisonValue获取Expression<Func<TSource, boolean>>的方法,以便它可以通过以下方式转换为商店表达式:实体框架。

这意味着琐碎

public static Expression<Func<TSource, bool>> KeyPredicateNaive<TSource, Tproperty>(Expression<Func<TSource, Tproperty>> keySelector, Tproperty comparisonValue)
{
  return (TSource source) =>EqualityComparer<Tproperty>.Default.Equals(keySelector.Compile()(source), comparisonValue);
}

不行。 这不能转换为商店表达式。

我们需要手动构造表达式。 我们需要的是一个使用键选择器作为其左值的相等表达式,以及一个将比较值作为值作为其右值的常量表达式。 我们可以构建如下:

public static Expression<Func<TSource, bool>> KeyPredicate<TSource, Tproperty>(Expression<Func<TSource, Tproperty>> keySelector, Tproperty comparisonValue)
{
  var bd = Expression.Equal(keySelector.Body, Expression.Constant(comparisonValue));
  return Expression.Lambda<Func<TSource, bool>>(bd, keySelector.Parameters);
}

结果可以传递给你的where类。 减肥(这样它将编译和运行),你的方法将是

public static IQueryable<TSource> GetPage<TSource>(this IQueryable<TSource> source,
    int pageSize,
    Expression<Func<TSource, Tproperty>> keySelector, Tproperty comparisonValue)
{
    return source
    .Where(KeyPredicate(keySelector, comparisonValue)
    .Take(pageSize);
}

我会用这个吗? 可能不是。 全方位将谓词作为lambda直接传递给函数,而不是自己构造表达式。 但这肯定是一种可能性。

您正在为可查询源编写扩展,是吗? 所以只需传递表达式和过滤源:

public static IQueryable<TSource> GetPage<TSource, TKey>(this IQueryable<TSource> source,
    Expression<Func<TSource, bool>> predicate,
    Expression<Func<TSource, TKey>> keySelector,
    int pageNr, int pageSize
    )
{
    return  source
       .Where(predicate)
       .OrderBy(keySelector)
       .Skip(pageNr * pageSize)
       .Take(pageSize);
}

用法:

db.Posts.GetPage(p => p.Author == "Bob", p => p.Date, 5, 10);

注意 :在你的方法中你有排序问题(第二个表达式),所有你得到的是传递两个参数p => p.Author, "Bob"而不是传递一个现成的表达式p => p.Author == "Bob"


但我会将谓词和keySelector移出GetPage方法。 让这个方法关注分页 (作为方法名称状态):

public static IQueryable<TSource> GetPage<TSource, TKey>(this IQueryable<TSource> source,
    int pageNr, int pageSize)
{
    return  source.Skip(pageNr * pageSize).Take(pageSize);
}

用法:

db.Posts.Where(p => p.Author == "Bob").OrderBy(p => p.Date).GetPage(5, 10);

或者如果你有存储库

postsRepository.GetByAuthor("Bob").GetPage(5, 10);

尝试这个,看看它是否有帮助

Expression<Func<TSource, bool>> keySelector

或者干脆

Func<TSource, bool> keySelector

鉴于此代码:

sealed class SwapVisitor : ExpressionVisitor
{
    private readonly Expression _from;
    private readonly Expression _to;

    public SwapVisitor(Expression from, Expression to)
    {
        _from = from;
        _to = to;
    }

    public override Expression Visit(Expression node)
    {
        return node == _from ? _to : base.Visit(node);
    }
}

static Expression<Func<TInput, bool>> Combine<TInput, TOutput>(
    Expression<Func<TInput, TOutput>> transform,
    Expression<Func<TOutput, bool>> predicate)
{
    var swap = new SwapVisitor(predicate.Parameters[0], transform.Body);
    return Expression.Lambda<Func<TInput, bool>>(
        swap.Visit(predicate.Body), transform.Parameters);
}

您可以:

 .Where(Combine(keySelector, key => key == comparisonValue))

这就是创建一个新的Expression ,其中包含传递的表达式keySelector的主体和用于比较的新表达式。

感谢Combine Lambda表达式

暂无
暂无

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

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