如何在c#中使用函数/表达式创建查询对象

本文关键字:表达式 创建 查询 对象 函数 | 更新日期: 2023-09-27 18:02:18

我想为我的项目创建一个使用ElasticSearch的可重用查询对象。我已经使用类似的QueryObject从工作/存储库的通用单元LongLe查询数据库使用实体框架。

我似乎真的不知道该怎么做——我不确定如何将lambda表达式的各个部分"链接"在一起。我试过使用表达式/函数,但这对我来说是一个新的领域,我不完全理解。我觉得自己就像在黑暗中捅刀子一样。

由于我甚至不知道如何准确地表达我的问题,这里有一个例子,说明我目前正在做什么,我正在努力做什么,以及我到目前为止的进展:

我现在要做的:

    ISearchResponse<DemoIndexModel> result = client.Search<DemoIndexModel>(s => s.Query(
        q => q.Term(t => t.FirstName, firstName)
        && q.Term(t => t.LastName, lastName)));

我想做的:

    var query = new DemoIndexQuery();
    query = query.ByFirstName(firstName);
    query = query.ByLastName(lastName);
    result = client.Search<DemoIndexModel>(s => s.Query(query.Compile()));

目前代码:

public abstract class ElasticQueryObject<T> where T : class
    {
        private Func<QueryDescriptor<T>, QueryContainer> _query;
        // tried using Expression, still completely lost
        private Expression<Func<QueryDescriptor<T>, QueryContainer>> _expression;
        public Func<QueryDescriptor<T>, QueryContainer> Compile()
        {
            return _query;
        }
        public Func<QueryDescriptor<T>, QueryContainer> And(Func<QueryDescriptor<T>, QueryContainer> query)
        {
            if (_query == null)
            {
                _query = query;
            }
            else
            {
                // how do I chain the query??? I only can figure out how to set it.
            }
            return null;
        }
    }
    public class DemoIndexQuery : ElasticQueryObject<DemoIndexModel>
    {
        public DemoIndexQuery ByFirstName(string firstName)
        {
            And(p => p.Term(term => term.FirstName, firstName));
            return this;
        }
        public DemoIndexQuery ByLastName(string lastName)
        {
            And(p => p.Term(term => term.LastName, lastName));
            return this;
        }
    }

如何在c#中使用函数/表达式创建查询对象

你违反了LINQ合同。查询应该是不可变的——对查询进行操作的所有方法都应该返回一个新的查询,而不是修改旧的查询。由于查询的构建方式,这在本质上是可组合的,所以不用

public DemoIndexQuery ByFirstName(string firstName)
{
    And(p => p.Term(term => term.FirstName, firstName));
    return this;
}

你可以这样写:

public DemoIndexQuery ByFirstName(string firstName)
{
    return Where(p => p.Term(term => term.FirstName, firstName));
}

如果由于某种原因不能这样做,则需要在传递表达式树之前自己处理构建表达式树的问题。最简单的方法是这样的:

Expression<...> oldQuery = ...;
var newCondition = (Expression<...>)(p => p.Term(...));
return Expression.And(oldQuery, newCondition);

如果您的查询提供程序不支持这个,您将需要更多的工作—您可以自己单独构建整个where谓词,然后确保您修复了lambdas和lambda参数。