【问题标题】:How to specify parameters for expression in C#如何在 C# 中为表达式指定参数
【发布时间】:2021-08-16 09:43:12
【问题描述】:

我正在尝试编写一个处理全文搜索的 Sql 扩展方法。

public static class StringSearchExtensions
{
    public static IQueryable<T> SearchByWords<T>(this IQueryable<T> query, string pattern)
    {

        var tokens = pattern
            .Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

        return tokens.Aggregate(query, (current, token) =>
            current.Where(x=> 
                PgSql.Ilike(x.TextField, $"%{token}%")));
    }
}

TextField 是我需要从调用代码中指定的字段。

PgSql是我的另一个扩展类,包含Ilike方法,它只是应用了psql的ILike方法。

我需要将参数x=&gt;x.Textfield 与我的参数一起传递。

【问题讨论】:

  • 真正的问题是什么?这个函数怎么调用?
  • 对了,你知道DbFunctions.LikeSqlMethods.Like吗?也许这符合您的需求。
  • 的限制呢? public static IQueryable&lt;T&gt; SearchByWords&lt;T&gt;(this IQueryable&lt;T&gt; query, string pattern) where T: ITextFieldContained
  • 通常你会使用“表达式”,比如Expression&lt;Func&lt;T, string&gt;&gt;,以便能够将该方法转换为等效的 SQL,但我不知道它是否可以与类似查询一起使用,因为它似乎期望一个实际的字符串。
  • @JonasH 是的,你是对的,这就是我想要做的,但遗憾的是,它不起作用。

标签: c# iqueryable


【解决方案1】:

这似乎有效。它不是很漂亮,而且我不能保证引擎可以将其转换为 SQL,但它实际上可以满足您的要求。

public static IQueryable<T> SearchByWords<T>(
  this IQueryable<T> query, Expression<Func<T, string>> expr, string pattern)
{
  var tokens = pattern
      .Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

  var prop = expr.Compile();
  return tokens.Aggregate(query, (current, token) =>
      current.Where(x => PgSql.Ilike(prop.Invoke(x), $"%{token}%")));
}

会这样称呼:

var byWords = tests.SearchByWords(x => x.TextField, "myTokens");

【讨论】:

  • 此代码示例与传递 Func 而不是 Expression> 没有什么不同。在这种情况下,我的表达式树有问题,它不适用于我的 ORM。
【解决方案2】:

要解决问题的关键部分,您需要一种方法将一个表达式的参数与另一个表达式的主体交换;

Expression<Func<A, C>> Apply<A, B, C>(Expression<Func<A, B>> expr1, Expression<Func<B, C>> expr2)
    => Expression.Lambda<Func<A, C>>(
        ReplacingExpressionVisitor.Replace(
            expr2.Parameters[0],
            expr1.Body,
            expr2.Body
        ),
        expr1.Parameters[0]
    );

现在以您的问题为例;

Expression<Func<T, string>> fieldExpr = x => x.Textfield;
var likeArg = $"%{token}%";
Expression<Func<string, bool>> likeExpr = str => PgSql.Ilike(str, likeArg);

var filter = Apply(fieldExpr, likeExpr);
// filter should now be equivalent to;
Expression<Func<T, bool>> expected = x => PgSql.Ilike(x.Textfield, likeArg);

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2018-07-30
  • 1970-01-01
  • 1970-01-01
  • 2021-06-09
  • 2020-08-18
  • 2019-05-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多