C# 构建动态Lambda表达式
做CURD开发的过程中,通常都会需要GetList,然而查询条件是一个可能变化的需求,如何从容对应需求变化呢?
首先,我们来设计一个套路,尝试以最小的工作量完成一次查询条件的需求变更
1.UI收集查询数据
2.UI将查询数据传递给Service
3.Service从查询配置(数据库、JSON、XML)中匹配出查询条件,并赋予UI取得的值
4.Service根据查询配置(已赋值)构建查询表达式。
5.执行查询返回数据。
大概流程如下图所示:
下面上代码,希望有人能看懂 ><
查询保存设置
- public interface IEntity
- {
- int Id { get; set; }
- }
- public class QueryCondition : IEntity
- {
- [Key]
- public int Id { get; set; }
- /// <summary>
- /// 条件分组:以此做为查询条件
- /// </summary>
- public string Group { get; set; }
- /// <summary>
- /// 字段名称
- /// </summary>
- public string FieldName { get; set; }
- public int CompareType { get; set; }
- public int CompareDataType { get; set; }
- public string Value { get; set; }
- }
查询条件DTO模型
- /// <summary>
- /// 查询结构
- /// </summary>
- public class QueryConditionModel
- {
- public string FieldName { get; set; }
- public CompareType Type { get; set; }
- public CompareDataType DataType { get; set; }
- public string Value { get; set; }
- }
- public enum CompareType
- {
- Equal = ,
- GreaterThan = ,
- GreaterThanOrEqual = ,
- LessThan = ,
- LessThanOrEqual = ,
- Include = ,
- }
- public enum CompareDataType
- {
- Int = ,
- String = ,
- Double = ,
- Decimal = ,
- Float = ,
- DateTime =
- }
查询条件DTO转换配置
- public class QueryConditionProfile : Profile
- {
- [Obsolete("")]
- protected override void Configure()
- {
- CreateMap<QueryCondition, QueryConditionModel>()
- .ForMember(p => p.Type, opt =>
- {
- opt.MapFrom(k => (CompareType)k.CompareType);
- })
- .ForMember(p => p.DataType, opt =>
- {
- opt.MapFrom(k => (CompareDataType)k.CompareDataType);
- })
- ;
- }
- }
查询条件构建
- public class ServiceBase
- {
- protected XXXDbContext Ctx;
- /// <summary>
- /// 动态构建Lambda查询表达式
- /// </summary>
- /// <param name="searchItems"></param>
- /// <returns></returns>
- protected Expression<Func<T, bool>> BuildExpression<T>(IList<QueryConditionModel> searchItems)
- {
- var where = PredicateExtensionses.True<T>();
- if (!searchItems.Any()) return @where;
- foreach (var subitem in searchItems)
- {
- try
- {
- var field = subitem.FieldName;
- var compare = subitem.Type;
- var type = subitem.DataType;
- var value = subitem.Value;
- if (string.IsNullOrEmpty(field)) continue;
- if (string.IsNullOrEmpty(value)) continue;
- //构建Lambda表达式
- var parameter = Expression.Parameter(typeof(T), "p");
- Expression constant;
- //表达式左侧 like: p.Name
- var left = Expression.PropertyOrField(parameter, field);
- //表达式右侧,比较值, like '张三'
- var right = Expression.Constant(value);
- //比较表达式
- switch (compare)
- {
- case CompareType.GreaterThan:
- constant = Expression.GreaterThan(left, right);
- break;
- case CompareType.GreaterThanOrEqual:
- constant = Expression.GreaterThanOrEqual(left, right);
- break;
- case CompareType.LessThan:
- constant = Expression.LessThan(left, right);
- break;
- case CompareType.LessThanOrEqual:
- constant = Expression.LessThanOrEqual(left, right);
- break;
- case CompareType.Include:
- //like 查询,需要调用外部int或string的Contains方法
- var method = type == CompareDataType.Int
- ? typeof(int).GetMethod("Contains", new Type[] { typeof(int) })
- : typeof(string).GetMethod("Contains", new Type[] { typeof(string) });
- constant = Expression.Call(left, method, right);
- break;
- case CompareType.Equal:
- default:
- constant = Expression.Equal(left, right);
- break;
- }
- var lambda = Expression.Lambda<Func<T, Boolean>>(constant, parameter);
- @where = @where.And(lambda);
- }
- catch (Exception ex)
- {
- //OnMethodExecuted(JsonConvert.SerializeObject(searchItems), JsonConvert.SerializeObject(ex), "",
- LogType.Error);
- }
- }
- return @where;
- }
- protected Expression<Func<T, bool>> GenerateConditions<T>(Dictionary<string, string> conditions, string fieldGroup)
- {
- //read query condition define
- var fields = Ctx.QueryConditions.Where(p => p.Group == fieldGroup).ToList();
- //read value from client conditions
- foreach (var condition in conditions)
- {
- SetValue(fields, condition.Key, condition.Value);
- }
- var businessCondigions = fields.Select(Mapper.Map<EntityFramework.QueryCondition, QueryConditionModel>).ToList();
- return BuildExpression<T>(businessCondigions);
- }
- private void SetValue(IList<EntityFramework.QueryCondition> conditions, string name, string value)
- {
- var field = conditions.FirstOrDefault(p => p.FieldName == name);
- if (field == null) return;
- field.Value = value;
- }
- }
调用示例:
- public IList<CustomerListModel> GetList(Dictionary<string,string> conditions, Pager pager)
- {
- try
- {
- var skip = (pager.PageIndex - ) * pager.PageSize;
- var where = GenerateConditions<EntityFramework.Customer>(conditions, "CustomerQueryModel");
- var query = Ctx.Customers.Include("MemberCard").WhereIf<EntityFramework.Customer>(where, pager);
- var list = query.Skip(skip).Take(pager.PageSize).ToList();
- var ret = new List<CustomerListModel>();
- foreach (var customer in list)
- {
- ret.Add(Mapper.Map<EntityFramework.Customer, CustomerListModel>(customer));
- }
- //OnMethodExecuted("GetList", "", "", LogType.Operate);
- return ret;
- }
- catch (Exception ex)
- {
- //OnErrorThrow(JsonConvert.SerializeObject(conditions), JsonConvert.SerializeObject(ex), ex.Message);
- throw ex;
- }
- }
C# 构建动态Lambda表达式的更多相关文章
- SqlDataReader生成动态Lambda表达式
上一扁使用动态lambda表达式来将DataTable转换成实体,比直接用反射快了不少.主要是首行转换的时候动态生成了委托. 后面的转换都是直接调用委托,省去了多次用反射带来的性能损失. 今天在对Sq ...
- 生成动态Lambda表达式1
SqlDataReader生成动态Lambda表达式 上一扁使用动态lambda表达式来将DataTable转换成实体,比直接用反射快了不少.主要是首行转换的时候动态生成了委托. 后面的转换都是直接调 ...
- c# ef 排序字段动态,构建动态Lambda和扩展方法OrderBy
1.动态构建排序 Lambda /// <summary> /// 获取排序Lambda(如果动态排序,类型不同会导致转换失败) /// </summary> /// < ...
- EntityFramework使用动态Lambda表达式筛选数据
public static class PredicateBuilder { public static Expression<Func<T, bool>> True<T ...
- 动态LINQ(Lambda表达式)构建
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; us ...
- 动态生成C# Lambda表达式
转载:http://www.educity.cn/develop/1407905.html,并整理! 对于C# Lambda的理解我们在之前的文章中已经讲述过了,那么作为Delegate的进化使用,为 ...
- Lambda表达式树构建(上)
概述 Lambda是C#常用的语句,采用委托等方式,来封装真实的代码块.Lambda其实就是语法糖,是一个匿名函数,是一种高效的类似于函数式编程的表达式,Lambda简化了开发中需要编写的代码量.它可 ...
- 动态Lambda表达式打印HelloWorld
最近在用C#与数据库打交道.开发过程中采用了ORM模型(以前是纯sql玩法,复杂的逻辑用存储过程做). 为了能通过配置文件动态地查询字段,也就是说需要能这样写: db.AsQuery<T> ...
- C# Lambda 表达式学习之(三):动态构建类似于 c => c.Age == null || c.Age > 18 的表达式
可能你还感兴趣: 1. C# Lambda 表达式学习之(一):得到一个类的字段(Field)或属性(Property)名,强类型得到 2. C# Lambda 表达式学习之(二):LambdaExp ...
随机推荐
- action(三)
CCSize boxSize = CCSizeMake(100.0f, 100.0f); CCLayerColor *box = CCLayerColor::create(ccc4(, , , )); ...
- 使用API Gateway
http://dockone.io/article/482 [编者的话]本系列的第一篇介绍了微服务架构模式.它讨论了采用微服务的优点和缺点,除了一些复杂的微服务,这种模式还是复杂应用的理想选择. Do ...
- iptables安装失败后-------------firewalld回归
yum install firewalld systemctl stop iptables; systemctl mask iptables; systemctl unmask firewalld s ...
- kafka启动及查看topic命令【已用过的,待更新】
以下均为开发测试环境下: 启动Zookeeperbin/zookeeper-server-start.sh config/zookeeper.properties &启动kafkabin/ka ...
- oracle 远程登录
打开命令终端,输入命令:sqlplus /nolog 输入命令:conn sys/sys@dba as sysdba
- 基于HTML5 Canvas生成粒子效果的人物头像
前面我们分享过一个HTML5 Canvas实现的图像马赛克模糊效果,HTML5处理图片真的非常简单.今天我们要再利用HTML5 Canvas实现一个粒子效果的人物头像,你可以任意选择一张头像图片,接下 ...
- C语言 · 排列数
算法提高 排列数 时间限制:1.0s 内存限制:256.0MB 问题描述 0.1.2三个数字的全排列有六种,按照字母序排列如下: 012.021.102.120.201.210 输入 ...
- LT和ET模式
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include &l ...
- Am335x 应用层之SPI操作
SPI接口有四种不同的数据传输时序,取决于CPOL和CPHL这两位的组合.图1中表现了这四种时序, 时序与CPOL.CPHL的关系也可以从图中看出. 图1 CPOL是用来决定SCK时钟信号空闲时的电平 ...
- Redis学习笔记——数据类型及操作
数据操作 redis是key-value的数据,所以每个数据都是一个键值对 键的类型是字符串 值的类型分为五种: 字符串string 哈希hash 列表list 集合set 有序集合zset 数据操作 ...