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 ...
随机推荐
- I2C总线协议
1.I2C协议 2条双向串行线,一条数据线SDA,一条时钟线SCL. SDA传输数据是大端传输,每次传输8bit,即一字节. 支持多主控(multimastering),任何时间点只能有 ...
- 03、矢量图形查询工具(Symbol Unicode)
目前的软件开发中,很多地方都使用到了矢量图标,在 Metro app 的开发中,可以使用 Windows 系统图标(02.Universal app 中按钮图标使用 ),包括 Segoe UI Sym ...
- Logstash日志字段拆分grok
参考和测试网站:http://grokdebug.herokuapp.com 例如:test-39.dev.abc-inc.com Mon Apr 24 13:53:58 CST 2017 2017- ...
- 这不是bug,而是语言特性
分析编程语言缺陷的一种方法是把所有的缺陷归于3类:不该做的做了,该做的没做,该做但做得不合适. 在使用switch case时,如果使用缺省的 fall through,请一定在旁边注释,因为97%的 ...
- nyoj16矩形嵌套(第一道dp关于dag的题目)
http://acm.nyist.net/JudgeOnline/problem.php?pid=16 题意:有n个矩形,每个矩形可以用a,b来描述,表示长和宽.矩形X(a,b)可以嵌套在矩形Y(c, ...
- 卖座网一处SQL注射(Http Referer sqlinjection)
漏洞作者: 猪猪侠 漏洞详情 披露状态: 2015-01-13: 细节已通知厂商并且等待厂商处理中2015-01-14: 厂商已经确认,细节仅向厂商公开2015-01-24: 细节向核心白帽子及相关领 ...
- ExecuteNonQuery和ExecuteScalar的区别
ExecuteNonQuery 针对 Connection 执行 SQL 语句并返回受影响的行数. 返回值 受影响的行数. 备注 您可以使用 ExecuteNonQuery 来执行目录操作(例如查 ...
- DRBD(Distributed Replicated Block Device) 分布式块设备复制 进行集群高可用方案
DRBD是一个用软件实现的.无共享的.服务器之间镜像块设备内容的存储复制解决方案. 外文名 DRBD drbdadm 高级管理工具 drbdsetup 置装载进kernel的DRBD模块 drbdme ...
- C++ 类中的静态成员变量,静态成员函数
//类中的静态成员变量,静态成员函数 #define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std; /* ...
- php ut8声明
header("Content-type: text/html; charset=utf-8");