平时使用 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 当中搜索 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); }
可以看到已经变得十分简洁,这里仅仅作为抛砖引玉,其实还有更多高级的用法,这里不再赘述。
点击查看更多内容
为 TA 点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦