平时使用 LINQ 进行一些简单的条件拼接查询一般都会这样操作:
- public class SearchInputDto
- {public string ConditionA { get; set;}
- public int? ConditionB { get; set; }
- public string ConditionC { get; set; }
- }
这里有三个条件, 是前端传入的搜索条件, 然后我们来编写一个查询语句:
- public Task Search(SearchInputDto input)
- {
- var queryResult = _db.Where(z=>(input.ConditionA == null || z.Name == input.ConditionA)
- && (input.ConditionB == null || z.Number == input.ConditionB)
- && (input.ConditionC == null || z.Address == input.ConditionC));
- // 执行其他操作...
- return Task.FromResult(0);
- }
因为我们前端传入的条件不是固定的, 所以有可能会出现有的条件没有传入的情况, 如果是 SQL 的话拼接 SQL 就可以了, 而 Linq 你肯定是没法拼接的, 只有自己构建一个表达式树传入到
IQuerable<T>.Where(Expression<Func<T,bool>> expression)
里面进行查询.
纯手工构建表达式树也不是不可以, 只是略微麻烦, 而我们则可以借助
System.Linq.Dynamic.Core
来方便的实现动态查询语句拼接.
他的常规用法如下:
官方 WIKI 地址: https://github.com/StefH/System.Linq.Dynamic.Core/wiki/Dynamic-Expressions
- var query = db.Customers
- .Where("City == @0 and Orders.Count>= @1", "London", 10)
- .OrderBy("CompanyName")
- .Select("new(CompanyName as Name, Phone)");
既然是字符串那么就可以拼接, 我们来做一下改造.
首先去 NuGet 当中搜索 https://www.nuget.org/packages/System.Linq.Dynamic.Core 库, 安装之后我们来重新编写之前的查询范例, 首先我们来写一个构建器, 用于构建我们的表达式树:
- using Abp.Runtime.Caching;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Linq.Dynamic.Core;
- using System.Linq.Expressions;
- using System.Reflection;
- using System.Text;
- namespace Abp.Linq.Expressions
- {
- public class ExpressionBuilder<TEntity, TSearchDto>
- {
- // 其实这里也可以通过传入 params Expression<Func<TRelateEntity, object>>[] selectFields 来构建
- public Expression<Func<TEntity, bool>> Build(string[] excludeFields, TSearchDto dto)
- {
- var parameters = GenerateParametersDictionary(excludeFields, dto);
- StringBuilder sb = new StringBuilder();
- var fieldNames = parameters.Keys.ToList();
- // 动态拼接
- for (int i = 0; i <fieldNames.Count; i++)
- {
- sb.Append(fieldNames[i]).Append($"== @{i}").Append("&&");
- }
- var lambdaStr = sb.ToString();
- lambdaStr = lambdaStr.Substring(0, lambdaStr.Length - "&&".Length);
- // 构建表达式
- return DynamicExpressionParser.ParseLambda<TEntity, bool>(new ParsingConfig(), false, lambdaStr, parameters.Values.ToArray());
- }
- // 构建参数 / 值键值对, 如果参数值为 NULL 则不进行构建
- private Dictionary<string, object> GenerateParametersDictionary(string[] excludeFields, TSearchDto dto)
- {
- var typeInfo = typeof(TSearchDto);
- var properties = typeInfo.GetProperties();
- var parameters = new Dictionary<string, object>();
- foreach (var property in properties)
- {
- var propertyValue = property.GetValue(dto);
- if (propertyValue == null) continue;
- if (excludeFields == null) continue;
- if (excludeFields.Contains(property.Name)) continue;
- if (parameters.ContainsKey(property.Name)) continue;
- parameters.Add(property.Name, propertyValue);
- }
- return parameters;
- }
- }
- }
用法很简单, 用刚才的代码作为一个例子:
- public Task Search(SearchInputDto input)
- {
- var builder = new ExpressionBuilder<EntityA,SearchInputDto>();
- var queryResult = _db.Where(builder.Build(null,input));
- // 执行其他操作...
- return Task.FromResult(0);
- }
可以看到已经变得十分简洁, 这里仅仅作为抛砖引玉, 其实还有更多高级的用法, 这里不再赘述.
来源: https://www.cnblogs.com/myzony/p/9143692.html