【问题标题】:Entity Framework build OR and pass to Where实体框架构建 OR 并传递到 Where
【发布时间】:2014-01-10 14:19:32
【问题描述】:

我想知道我该怎么做? 事实是我有一个带有搜索条件的对象(一些要搜索的字段表示条件)。我需要根据条件构建查询,但它使用 AND 加入 where。 这就是我所拥有的:

public class SearchCriteria
{
    public SearchCriteria()
    {
        this.Theme = new HashSet<int>();
    }

    public string KeyWord { get; set; }
    public bool? ChildrenFirstCycle  { get; set; }
    public bool? ChildrenSecondCycle { get; set; }
    public bool? Primary { get; set; }
    public bool? Secondary { get; set; }
    public bool? BachelorArts { get; set; }
    public bool? BachelorHumanities { get; set; }
    public bool? BachelorScience { get; set; }
    public bool? University { get; set; }
    public bool? MediumLevelCycle { get; set; }
    public bool? HighLevelCycle { get; set; }
    public int? DistrictID { get; set; }
    public int? CountyID { get; set; }
    public int? MunicipalID { get; set; }
    public ICollection<int> Theme { get; set; }
}

    public IEnumerable<School> GetAllEscuelasBySearchCriteria(SearchCriteria searchCriteria)
    {
        var Query = this._repository.Retrieve();

        if (!string.IsNullOrWhiteSpace(searchCriteria.KeyWord))
        {
            Query = Query.Where(p => p.Name.Contains(searchCriteria.KeyWord) || p.Grade.Contains(searchCriteria.KeyWord) || p.Email.Contains(searchCriteria.KeyWord) || p.Address.Contains(searchCriteria.KeyWord) || p.Code.Contains(searchCriteria.KeyWord));
        }

        //Rest of condition
        if (RestConditions)
        {
            Query = Query.Where(p=> REST CONDITIONS);
        }

        //I need to create a list of func expression and add each expression pass the condition and then a foreach and do an OR for all in List of FUNC

        if (searchCriteria.InfantilFirstCycle.HasValue && searchCriteria.InfantilFirstCycle.Value != false)
        {
            Query = Query.Where(p => (p.value1 > 0 || p.value2 > 0 || p.value3 > 0));
        }
        if (searchCriteria.InfantilSecondCycle.HasValue && searchCriteria.InfantilSecondCycle.Value != false)
        {
            Query = Query.Where(p => (p.value4 > 0 || p.value5 > 0 || p.value6 > 0));
        }
        if (searchCriteria.Primary.HasValue && searchCriteria.Primary.Value != false)
        {
            Query = Query.Where(p => (p.value7 > 0 || p.value8 > 0 || p.value9 > 0 || p.value10 > 0 || p.value11 > 0 || p.value13 > 0 || p.value14 > 0));
        }

        return Query.Distinct().OrderBy(c=>c.Name).ToList();
    }

【问题讨论】:

  • 我遇到了这个确切的问题,最终使用了动态 linq。github.com/kahanu/System.Linq.Dynamic
  • 我试过但说 base {System.Exception} = {"LINQ to Entities 不支持 LINQ 表达式节点类型 'Invoke'。"}

标签: entity-framework lambda where func


【解决方案1】:

查看这个在 IQueryable 上启用搜索扩展的 nuget 包。

https://www.nuget.org/packages/NinjaNye.SearchExtensions/

它将允许您执行以下操作:

var query = this._repository.Retrieve();

query = query.Search(searchCriteria.KeyWord, p => p.Name, p => p.Email, p => p.Address, p => p.Code)
             .Where(p => searchCriteria.InfantilFirstCycle == true && (p.value1 > 0 || p.value2 > 0 || p.value3 > 0))
             .Where(p => searchCriteria.InfantilSecondCycle == true && (p.value4 > 0 || p.value5 > 0 || p.value6 > 0))
             .Where(p => searchCriteria.Primary == true && (p.value7 > 0 || p.value8 > 0 || p.value9 > 0 || p.value10 > 0 || p.value11 > 0 || p.value13 > 0 || p.value14 > 0))

return query.Distinct().OrderBy(c=>c.Name).ToList();

这里有源代码以及一些示例用法:

https://github.com/ninjanye/SearchExtensions

对于额外的 where 子句,您可以调整 searchextensions 代码以满足您的需要。类似下面的内容将启用以下语法:

    var query = this._repository.Retrieve();    
    query = query.Search(searchCriteria.KeyWord, 
                         p => p.Name, 
                         p => p.Email, 
                         p => p.Address, 
                         p => p.Code)

    if(searchCriteria.InfantilFirstCycle == true)
    {
        query = query.IntGreaterThan(0, p => p.value1, p => p.value2, p => p.value3);            
    }

    if(searchCriteria.InfantilSecondCycle == true)
    {
        query = query.IntGreaterThan(0, p => p.value4, p => p.value5, p => p.value6);            
    }

    if(searchCriteria.Primary == true)
    {
        query = query.IntGreaterThan(0, p => p.value7, p => p.value8, p => p.value9, p => p.value10, p => p.value11, p => p.value13, p => p.value14);
    }

    return query.Distinct().OrderBy(c=>c.Name).ToList(); 

这是启用上述功能的代码。 (请注意,这是在未经测试的情况下编写的,可能需要调整)

public static class Extensions
{
    public static IQueryable<T> IntGreaterThan<T>(this IQueryable<T> source, int greaterThanValue, params Expression<Func<T, int>>[] integerProperties)
    {
        //Variable to hold merged 'OR' expression
        Expression orExpression = null;

        //Retrieve first parameter to use accross all expressions
        var singleParameter = integerProperties[0].Parameters.Single();

        //Create a constant to represent the search term
        ConstantExpression greaterThanExpression = Expression.Constant(greaterThanValue)

        //Build a contains expression for each property
        foreach (var intProperty in integerProperties)
        {
            //Syncronise single parameter accross each property
            var swappedParamExpression = SwapExpressionVisitor.Swap(intProperty, intProperty.Parameters.Single(), singleParameter);

            //Build expression to represent x.[propertyX] > greaterThanValue
            var expression = BuildGreaterThanExpression(swappedParamExpression, greaterThanExpression);

            //Add contains expresion to the existing expression
            orExpression = BuildOrExpression(orExpression, expression);
        }     

        var completeExpression = Expression.Lambda<Func<T, bool>>(orExpression, singleParameter);
        return source.Where(completeExpression);
    }

    private static BinaryExpression BuildGreaterThanExpression<T>(Expression<Func<T, int>> intProperty, ConstantExpression greaterThanExpression)
    {
        return Expression.GreaterThan(intProperty.Body, greaterThanExpression);
    }

    /// <summary>
    /// Connect to expressions using the OrElse expression
    /// </summary>
    private static Expression BuildOrExpression(Expression existingExpression, Expression expressionToAdd)
    {
        if (existingExpression == null)
        {
            return expressionToAdd;
        }

        //Build 'OR' expression for each property
        return Expression.OrElse(existingExpression, expressionToAdd);
    }
}


internal class SwapExpressionVisitor : ExpressionVisitor
{
    private readonly Expression from, to;
    private SwapExpressionVisitor(Expression from, Expression to)
    {
        this.@from = @from;
        this.to = to;
    }

    public static Expression<T> Swap<T>(Expression<T> lambda, Expression from, Expression to)
    {
        return Expression.Lambda<T>(
            Swap(lambda.Body, from, to), lambda.Parameters);
    }

    private static Expression Swap(Expression body, Expression from, Expression to)
    {
        return new SwapExpressionVisitor(from, to).Visit(body);
    }

    public override Expression Visit(Expression node)
    {
        return node == this.@from ? this.to : base.Visit(node);
    }
}    

【讨论】:

  • 正是我想要的。很棒的包。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-31
  • 1970-01-01
  • 2022-01-06
  • 2021-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多