如何在C#中使用Func/表达式创建查询对象?

如何在C#中使用Func/表达式创建查询对象?,c#,expression,nest,func,C#,Expression,Nest,Func,我想为使用ElasticSearch的项目创建一个可重用的查询对象。我已经在使用LongLe提供的类似工具来查询使用实体框架的数据库 我真的不知道该怎么做——我不知道如何将lambda表达式的各个部分“链接”在一起。我尝试过使用Expression/Func,但这对我来说是一个新领域,我并不完全理解。我觉得自己就像是在黑暗中刺伤 由于我甚至不知道如何准确地表达我的问题,下面是一个我目前正在做的事情、我正在尝试做的事情以及我迄今为止的进展的例子: 我目前必须做的事情: ISearchRes

我想为使用ElasticSearch的项目创建一个可重用的查询对象。我已经在使用LongLe提供的类似工具来查询使用实体框架的数据库

我真的不知道该怎么做——我不知道如何将lambda表达式的各个部分“链接”在一起。我尝试过使用Expression/Func,但这对我来说是一个新领域,我并不完全理解。我觉得自己就像是在黑暗中刺伤

由于我甚至不知道如何准确地表达我的问题,下面是一个我目前正在做的事情、我正在尝试做的事情以及我迄今为止的进展的例子:

我目前必须做的事情:

    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;
        }
    }
ISearchResponse结果=client.Search(s=>s.Query(
q=>q.Term(t=>t.FirstName,FirstName)
&&术语(t=>t.LastName,LastName));
我想做什么:

    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;
        }
    }
var query=new DemoIndexQuery();
query=query.ByFirstName(firstName);
query=query.ByLastName(lastName);
结果=client.Search(s=>s.Query(Query.Compile());
到目前为止的代码:

    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;
        }
    }
公共抽象类ElasticQueryObject,其中T:class
{
私有函数查询;
//尝试使用表达式,但仍然完全失败
私人表达(private Expression);
公共函数编译()
{
返回查询;
}
公共函数和(函数查询)
{
if(_query==null)
{
_查询=查询;
}
其他的
{
//如何链接查询???我只知道如何设置查询。
}
返回null;
}
}
公共类DemoIndexQuery:ElasticQueryObject
{
public DemoIndexQuery ByFirstName(字符串名)
{
和(p=>p.Term(Term=>Term.FirstName,FirstName));
归还这个;
}
公共DemoIndexQuery ByLastName(字符串lastName)
{
和(p=>p.Term(Term=>Term.LastName,LastName));
归还这个;
}
}

您正在违反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);
表达式oldQuery=。。。;
var newCondition=(表达式)(p=>p.Term(…);
返回表达式和(oldQuery、newCondition);

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

那么,问题出在哪里?除了不返回修改后的查询之外,我的意思是,查询对象不是不起作用的部分,我试图理解如何链接表达式的各个部分。我没有
Where()
选项。如何准确地为Func构建表达式树?@DoctorOreo
expression
是一个lambda表达式-您可以使用
expression.lambda
创建它。棘手的部分是正确映射lambda参数-您需要在声明中使用相同的
ParameterExpression
,以后再使用。