【问题标题】:How to write dynamic where clause for join range varible如何为连接范围变量编写动态where子句
【发布时间】:2016-08-23 06:23:01
【问题描述】:

我一直在使用 LINQ 进行查询,但我遇到了动态 where 子句的障碍。我想检查一个条件,如果为真,然后将其添加到我的查询中。问题是 where 正在使用我的一个连接中的一个范围变量。我的工作查询如下:

var query = from project in db.ProjMasters
             join pd in db.ProjDetails on project.ProjMasterID equals pd.ProjMasterID
             join dc in db.DivCodes on project.DivisionCode equals dc.DivCode1
             join ec in db.EmpCodes on project.ProjManager equals ec.UserNm
             join ptc in db.ProjTypeCodes on pd.ProjTypeCode equals ptc.ProjTypeCode1
             join psc in db.ProjStatusCodes on pd.ProjStatusCode equals psc.ProjStatusCode1
             where pd.ProjDeleteDate == null
             orderby project.Title
             select new
             {
                  project.ProjMasterID,
                  project.Title,
                  pd.ProjDesc,
                  pd.ContractNum,
                  pd.ProjDetailID,
                  dc.DivNm,
             }
             if (sTitle != null)
             {
                 query = query.Where(x => x.Title.Contains(sTitle));
             }

TypeDesc 是 db.ProjTypeCodes 中的一个类型,所以我想说

if (sProjType != null)
{
    query = query.Where(x => x.TypeDesc==sProjType);
}

但我只能在项目中使用 where 类型; “AnonymousType#1 不包含 'TypeDesc' 的定义...”如何在 ptc.TypeDesc 上使用动态 where?

【问题讨论】:

  • 嗯,错误很明显,您没有选择 ptc.TypeDesc,只需将其添加到您的选择中...
  • 感谢古斯曼!如果你知道我已经在这个圈子里转了多长时间。

标签: c# asp.net entity-framework linq


【解决方案1】:

问题在于您的订单,在选择时您将丢弃所有不在选择语句中的数据,如果您使用内联 if 语句,那么您可以在第一个 where 子句中轻松完成,或者您可以在之后将选择分开您可能需要从 Linq 查询转换为 linq statments

var query = from project in db.ProjMasters
             join pd in db.ProjDetails on project.ProjMasterID equals pd.ProjMasterID
             join dc in db.DivCodes on project.DivisionCode equals dc.DivCode1
             join ec in db.EmpCodes on project.ProjManager equals ec.UserNm
             join ptc in db.ProjTypeCodes on pd.ProjTypeCode equals ptc.ProjTypeCode1
             join psc in db.ProjStatusCodes on pd.ProjStatusCode equals psc.ProjStatusCode1
             where pd.ProjDeleteDate == null
                && sProjType!= null ? ptc.TypeDesc==sProjType): true
             orderby project.Title
             select new
             {
                  project.ProjMasterID,
                  project.Title,
                  pd.ProjDesc,
                  pd.ContractNum,
                  pd.ProjDetailID,
                  dc.DivNm,
             }
             if (sTitle != null)
             {
                 query = query.Where(x => x.Title.Contains(sTitle));
             }

【讨论】:

  • 由于某种原因,这种方式返回的记录多于 Gusman 的方式,后者返回正确的数字(与原始 sql 查询相比)。
【解决方案2】:

您的查询非常适合尝试我最近发布到"Nullable object must have a value" exception after checking for null on a non-primitive/non-struct object 的自定义扩展方法。

这个想法很简单。您直接在查询中构建动态条件,该方法将其转换为就像您使用 ifs 一样:

var query = (from project in db.ProjMasters
             join pd in db.ProjDetails on project.ProjMasterID equals pd.ProjMasterID
             join dc in db.DivCodes on project.DivisionCode equals dc.DivCode1
             join ec in db.EmpCodes on project.ProjManager equals ec.UserNm
             join ptc in db.ProjTypeCodes on pd.ProjTypeCode equals ptc.ProjTypeCode1
             join psc in db.ProjStatusCodes on pd.ProjStatusCode equals psc.ProjStatusCode1
             where pd.ProjDeleteDate == null
                 && (sProjType == null || ptc.TypeDesc == sProjType)
                 && (sTitle == null || project.Title.Contains(sTitle))
             orderby project.Title
             select new
             {
                  project.ProjMasterID,
                  project.Title,
                  pd.ProjDesc,
                  pd.ContractNum,
                  pd.ProjDetailID,
                  dc.DivNm,
             }).ReduceConstPredicates();

附:以下是所用方法的源代码,以防链接发生问题:

public static class QueryableExtensions
{
    public static IQueryable<T> ReduceConstPredicates<T>(this IQueryable<T> source)
    {
        var reducer = new ConstPredicateReducer();
        var expression = reducer.Visit(source.Expression);
        if (expression == source.Expression) return source;
        return source.Provider.CreateQuery<T>(expression);
    }

    class ConstPredicateReducer : ExpressionVisitor
    {
        private int evaluateConst;
        private bool EvaluateConst { get { return evaluateConst > 0; } }
        private ConstantExpression TryEvaluateConst(Expression node)
        {
            evaluateConst++;
            try { return Visit(node) as ConstantExpression; }
            catch { return null; }
            finally { evaluateConst--; }
        }
        protected override Expression VisitUnary(UnaryExpression node)
        {
            if (EvaluateConst || node.Type == typeof(bool))
            {
                var operandConst = TryEvaluateConst(node.Operand);
                if (operandConst != null)
                {
                    var result = Expression.Lambda(node.Update(operandConst)).Compile().DynamicInvoke();
                    return Expression.Constant(result, node.Type);
                }
            }
            return EvaluateConst ? node : base.VisitUnary(node);
        }
        protected override Expression VisitBinary(BinaryExpression node)
        {
            if (EvaluateConst || node.Type == typeof(bool))
            {
                var leftConst = TryEvaluateConst(node.Left);
                if (leftConst != null)
                {
                    if (node.NodeType == ExpressionType.AndAlso)
                        return (bool)leftConst.Value ? Visit(node.Right) : Expression.Constant(false);
                    if (node.NodeType == ExpressionType.OrElse)
                        return !(bool)leftConst.Value ? Visit(node.Right) : Expression.Constant(true);
                    var rightConst = TryEvaluateConst(node.Right);
                    if (rightConst != null)
                    {
                        var result = Expression.Lambda(node.Update(leftConst, node.Conversion, rightConst)).Compile().DynamicInvoke();
                        return Expression.Constant(result, node.Type);
                    }
                }
            }
            return EvaluateConst ? node : base.VisitBinary(node);
        }
        protected override Expression VisitConditional(ConditionalExpression node)
        {
            if (EvaluateConst || node.Type == typeof(bool))
            {
                var testConst = TryEvaluateConst(node.Test);
                if (testConst != null)
                    return Visit((bool)testConst.Value ? node.IfTrue : node.IfFalse);
            }
            return EvaluateConst ? node : base.VisitConditional(node);
        }
        protected override Expression VisitMember(MemberExpression node)
        {
            if (EvaluateConst || node.Type == typeof(bool))
            {
                var expressionConst = node.Expression != null ? TryEvaluateConst(node.Expression) : null;
                if (expressionConst != null || node.Expression == null)
                {
                    var result = Expression.Lambda(node.Update(expressionConst)).Compile().DynamicInvoke();
                    return Expression.Constant(result, node.Type);
                }
            }
            return EvaluateConst ? node : base.VisitMember(node);
        }
        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            if (EvaluateConst || node.Type == typeof(bool))
            {
                var objectConst = node.Object != null ? TryEvaluateConst(node.Object) : null;
                if (objectConst != null || node.Object == null)
                {
                    var argumentsConst = new ConstantExpression[node.Arguments.Count];
                    int count = 0;
                    while (count < argumentsConst.Length && (argumentsConst[count] = TryEvaluateConst(node.Arguments[count])) != null)
                        count++;
                    if (count == argumentsConst.Length)
                    {
                        var result = Expression.Lambda(node.Update(objectConst, argumentsConst)).Compile().DynamicInvoke();
                        return Expression.Constant(result, node.Type);
                    }
                }
            }
            return EvaluateConst ? node : base.VisitMethodCall(node);
        }
    }
}

【讨论】:

    【解决方案3】:

    在此处使用 IQueryable 可以了解更多信息,为什么 link

    IQueryable<{CreateNewSelectObjects}> query = ... ;
    if (sProjType != null)
    {
        query = query.Where(x => x.TypeDesc==sProjType);
    }
    

    【讨论】:

    • 不会有帮助,因为该字段不在数据集中了
    猜你喜欢
    • 1970-01-01
    • 2019-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-22
    • 1970-01-01
    相关资源
    最近更新 更多