我有一个带有多个条件where子句的linq查询。当where子句中没有过滤器时,查询将返回表中的所有数据。当where子句中没有过滤器时,如何使linq查询第一次返回0条记录?请参阅下面的代码:
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Web.Http;
using API.Models;
using System.Linq.Expressions;
namespace API.Controllers
{
// api代码从这里开始
public class MYTABLEController : ApiController
{
private DataModel db = new DataModel();
//GET /MYTABLE
public List<MYTABLE> Get(string filter1 = null,string filter2=null)
{
IQueryable<MYTABLE> qry = db.MYTABLE.AsQueryable();
var searchPredicate = PredicateBuilder.False<MYTABLE>();
if (!string.IsNullOrWhiteSpace(filter1))
{
searchPredicate = searchPredicate.And(a => a.COLUMN1==(filter1);
}
if (!string.IsNullOrWhiteSpace(filter2))
{
searchPredicate = searchPredicate.And(a => a.COLUMN2==(filter2);
}
return qry.Where(searchPredicate).ToList();
}
// PredicateBuilder https://petemontgomery.wordpress.com/2011/02/10/a-universal-predicatebuilder/
public static class PredicateBuilder
{
/// <summary>
/// Creates a predicate that evaluates to true.
/// </summary>
public static Expression<Func<T, bool>> True<T>() { return param => true; }
/// <summary>
/// Creates a predicate that evaluates to false.
/// </summary>
public static Expression<Func<T, bool>> False<T>() { return param => false; }
/// <summary>
/// Creates a predicate expression from the specified lambda expression.
/// </summary>
public static Expression<Func<T, bool>> Create<T>(Expression<Func<T, bool>> predicate) { return predicate; }
/// <summary>
/// Combines the first predicate with the second using the logical "and".
/// </summary>
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.AndAlso);
}
/// <summary>
/// Combines the first predicate with the second using the logical "or".
/// </summary>
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
{
return first.Compose(second, Expression.OrElse);
}
/// <summary>
/// Negates the predicate.
/// </summary>
public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> expression)
{
var negated = Expression.Not(expression.Body);
return Expression.Lambda<Func<T, bool>>(negated, expression.Parameters);
}
/// <summary>
/// Combines the first expression with the second using the specified merge function.
/// </summary>
static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
{
// zip parameters (map from parameters of second to parameters of first)
var map = first.Parameters
.Select((f, i) => new { f, s = second.Parameters[i] })
.ToDictionary(p => p.s, p => p.f);
// replace parameters in the second lambda expression with the parameters in the first
var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
// create a merged lambda expression with parameters from the first expression
return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
}
class ParameterRebinder : ExpressionVisitor
{
readonly Dictionary<ParameterExpression, ParameterExpression> map;
ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
{
this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
}
public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
{
return new ParameterRebinder(map).Visit(exp);
}
protected override Expression VisitParameter(ParameterExpression p)
{
ParameterExpression replacement;
if (map.TryGetValue(p, out replacement))
{
p = replacement;
}
return base.VisitParameter(p);
}
}
}
答案 0 :(得分:0)
首先,我将为此使用谓词构建器。例如this one。
这会将您的代码转换为:
IQyeryable<MyTable> qry = db.myTable;
var predicate = PredicateBuilder.True<MyTable>();
if (!string.IsNullOrWhiteSpace(filter1))
{
predicate = predicate.And(a => a.column1.Contains(filter1));
}
if (!string.IsNullOrWhiteSpace(filter2))
{
predicate = predicate.And(a => a.column2.Contains(filter2));
}
...
qry = qry.Where(predicate);
现在很容易检查是否添加了任何谓词。如果不是,则predicate
只是a => true
,这意味着它的主体只是一个ConstantExpression
(值:true
)。您可以在最后一行的上方添加此检查:
if (predicate.Body is ConstantExpression)
{
predicate = PredicateBuilder.False<MyTable>();
}
(当然,前提是您不要用另一个谓词,另一个常量表达式替换 predicate
,但是我想那没有多大意义)。
答案 1 :(得分:0)
像这样更新此方法:
public List<MYTABLE> Get(string filter1 = null,string filter2=null)
{
if(string.IsNullOrWhiteSpace(filter1) && string.IsNullOrWhiteSpace(filter2))
return new List<MYTABLE>();
IQueryable<MYTABLE> qry = db.MYTABLE.AsQueryable();
var searchPredicate = PredicateBuilder.False<MYTABLE>();
if (!string.IsNullOrWhiteSpace(filter1))
{
searchPredicate = searchPredicate.And(a => a.COLUMN1==(filter1);
}
if (!string.IsNullOrWhiteSpace(filter2))
{
searchPredicate = searchPredicate.And(a => a.COLUMN2==(filter2);
}
return qry.Where(searchPredicate).ToList();
}
答案 2 :(得分:0)
您可以创建扩展方法:
public static IQueryable<T> WhereIf<T>(
this IQueryable<T> source, bool condition,
Expression<Func<T, bool>> predicate)
{
return condition ? source.Where(predicate) : source;
}
并以以下方式使用它:
using static System.String;
...
public List<MYTABLE> Get(string filter1 = null,string filter2=null)
{
return db.MYTABLE
.WhereIf(!IsNullOrEmpty(filter1), y => y.COLUMN1 == filter1)
.WhereIf(!IsNullOrEmpty(filter2), y => y.COLUMN2 == filter2)
.ToList();
}