用于多级查询的动态Linq表达式 [英] Dynamic Linq Expression for multi-level query

查看:67
本文介绍了用于多级查询的动态Linq表达式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要动态构建以下Linq表达式.

I have the following Linq expression that I would like to build dynamically.

我遇到的问题是我无法构建表达式树来容纳复杂的Select/Any语句.我读过,为了使用方法,您必须按如下方式调用该方法:

The problem i'm running into is that I can't build the expression tree to accommodate the complex Select/Any statements. I have read that in order to use methods you literally have to invoke the method as in:

 Invoke("Any")


我需要动态构建的表达式:


Expression that I need built dynamically:

Expression<Func<TXLifeRequest, bool>> filter = (txreq) => 
txreq.IsDeleted == false &&
txreq.OLifE.Holding.Select(h => h.Policy)
    .Any(p => p.RequirementInfo
        .Any(r => r.ReqStatus.tc == OLI_LU_REQSTAT.OLI_REQSTAT_OUTSTANDING.tc));

var results = db.GetQueryable(filter)
                .Include(r => r.OLifE.Holding.Select(h => h.Policy)
                   .Select(p => p.RequirementInfo)).ToList();

这是我的模型课:

OLI_LU_REQSTAT

public partial class OLI_LU_REQSTAT : BaseType {

    public string tc { get; set; }

    public string Value { get; set; }
}


TXLifeRequest

public partial class TXLifeRequest : BaseEntity
{
    public virtual OLifE OLifE { get; set; }

    ...
}


OLifE

public partial class OLifE : BaseEntity
{
    public virtual List<Holding> Holding { get; set; }
        ...
}


保留

public class Holding : BaseEntity
{
    public virtual Policy Policy { get; set; }
    ...
}


政策

public class Policy : BaseEntity
{
    public virtual List<RequirementInfo> RequirementInfo { get; set; }

    ...
}


RequirementInfo

public partial class RequirementInfo : BaseEntity
{
     public virtual OLI_LU_REQSTAT ReqStatus { get; set; }

    ...
}   


当前,我正在针对GetProperty运行反射foreach,但无法理解文档以使对象模型降低3-4级:


Currently I am running a reflection foreach against GetProperty but have not been able to understand the documentation in order to get 3-4 levels down in the object model:

ParameterExpression parameter = Expression.Parameter(typeof(T), "i");
MemberExpression property = Expression.Property(parameter, propertyName);
ConstantExpression constant = Expression.Constant(val, propertyType);


var condition =
    Expression.Lambda<Func<T, bool>>(
        Expression.Equal(
            property,
            constant
        ),
        parameter
    );

result = AppendExpression(result, condition, result);


更新1.)添加了RequirementInfo.添加所有的类属性没有意义,因为那里有所需的类结构.


Update 1.) Added RequirementInfo. Adding all class properties would not make sense as the required class structure is there.

推荐答案

很长.我觉得要进行维护"太复杂了,如果需要进行一些更改,这将变得非常困难.甚至使其成为动态的"以便可以对其进行控制(启用或禁用零件)也很困难.

Quite long. I feel it is too much complex to be "maintainable", and if you need to do some changes, it becomes quite difficult. Even making it "dynamic" so that it can be controlled (enabling or disabling parts) is difficult.

给予

// Enumerable.Any()
static readonly MethodInfo anyTSource = (from x in typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public)
                                         where x.Name == nameof(Enumerable.Any)
                                         let args = x.GetGenericArguments()
                                         where args.Length == 1
                                         let pars = x.GetParameters()
                                         where pars.Length == 2 &&
                                             pars[0].ParameterType == typeof(IEnumerable<>).MakeGenericType(args[0]) &&
                                             pars[1].ParameterType == typeof(Func<,>).MakeGenericType(args[0], typeof(bool))
                                         select x).Single();

// Enumerable.Select()
public static readonly MethodInfo selectTSourceTResult = (from x in typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public)
                                                          where x.Name == nameof(Enumerable.Select)
                                                          let args = x.GetGenericArguments()
                                                          where args.Length == 2
                                                          let pars = x.GetParameters()
                                                          where pars.Length == 2 &&
                                                                    pars[0].ParameterType == typeof(IEnumerable<>).MakeGenericType(args[0]) &&
                                                                    pars[1].ParameterType == typeof(Func<,>).MakeGenericType(args[0], args[1])
                                                          select x).Single();

是LINQ Enumerable.Any()Enumerable.Select()

并给出了您的

// txreq => ((txreq.IsDeleted == False) AndAlso txreq.OLifE.Holding.Select(h => h.Policy).Any(p => p.RequirementInfo.Any(r => (r.ReqStatus.tc == OLI_LU_REQSTAT.OLI_REQSTAT_OUTSTANDING.tc))))
string str1 = filter.ToString();

将您的表达式与生成的表达式进行比较

to make a comparison of your expression with a generated expression

具有一些快捷方式(我使用!rxreq.IsDeleted代替了txreq.IsDeleted == False,而不是包含OLI_LU_REQSTAT.OLI_REQSTAT_OUTSTANDING.tc,而是在构建表达式树时读取了它的值并将其放在Expression.Constant()中,

with some shortcuts (instead of txreq.IsDeleted == False I use !rxreq.IsDeleted and instead of including OLI_LU_REQSTAT.OLI_REQSTAT_OUTSTANDING.tc I read its value when the expression tree is built and put it in an Expression.Constant(),

var par = Expression.Parameter(typeof(TXLifeRequest), "txreq");

// txreq.IsDeleted == false (simplified to !txreq.IsDeleted)
var notIsDeleted = Expression.Not(Expression.Property(par, "IsDeleted"));

// r => 
var par4 = Expression.Parameter(typeof(RequirementInfo), "r");

// OLI_LU_REQSTAT.OLI_REQSTAT_OUTSTANDING.tc
var oli_reqstat_outstanding_tc = Expression.Constant(OLI_LU_REQSTAT.OLI_REQSTAT_OUTSTANDING.tc);

// r.ReqStatus.tc == OLI_LU_REQSTAT.OLI_REQSTAT_OUTSTANDING.tc
Expression<Func<RequirementInfo, bool>> any2Lambda = Expression.Lambda<Func<RequirementInfo, bool>>(Expression.Equal(Expression.Property(Expression.Property(par4, "ReqStatus"), "tc"), oli_reqstat_outstanding_tc), par4);

// To check if it is correct
//any2Lambda.Compile();

// p => 
var par3 = Expression.Parameter(typeof(Policy), "p");

// p.RequirementInfo.Any(...)
Expression<Func<Policy, bool>> any1Lambda = Expression.Lambda<Func<Policy, bool>>(Expression.Call(anyTSource.MakeGenericMethod(typeof(RequirementInfo)), Expression.Property(par3, "RequirementInfo"), any2Lambda), par3);

// To check if it is correct
//any1Lambda.Compile();

// h => 
var par2 = Expression.Parameter(typeof(Holding), "h");

// h.Policy
Expression<Func<Holding, Policy>> selectLambda = Expression.Lambda<Func<Holding, Policy>>(Expression.Property(par2, "Policy"), par2);

// To check if it is correct
//selectLambda.Compile();

//txreq.OLifE.Holding
var holding = Expression.Property(Expression.Property(par, "OLifE"), "Holding");

// txreq.OLifE.Holding.Select(...)
var select = Expression.Call(selectTSourceTResult.MakeGenericMethod(typeof(Holding), typeof(Policy)), holding, selectLambda);
var any1 = Expression.Call(anyTSource.MakeGenericMethod(typeof(Policy)), select, any1Lambda);

var and = Expression.AndAlso(notIsDeleted, any1);

Expression<Func<TXLifeRequest, bool>> lambda = Expression.Lambda<Func<TXLifeRequest, bool>>(and, par);

// To check if it is correct and/or use it
//var compiled = lambda.Compile();

如果我们尝试lambda.ToString(),我们会得到:

if we try lambda.ToString() we get:

txreq => (Not(txreq.IsDeleted) AndAlso txreq.OLifE.Holding.Select(h => h.Policy).Any(p => p.RequirementInfo.Any(r => (r.ReqStatus.tc == "SOMEVALUE"))))

足够相似.

这篇关于用于多级查询的动态Linq表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆