做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表达式的更多相关文章

  1. SqlDataReader生成动态Lambda表达式

    上一扁使用动态lambda表达式来将DataTable转换成实体,比直接用反射快了不少.主要是首行转换的时候动态生成了委托. 后面的转换都是直接调用委托,省去了多次用反射带来的性能损失. 今天在对Sq ...

  2. 生成动态Lambda表达式1

    SqlDataReader生成动态Lambda表达式 上一扁使用动态lambda表达式来将DataTable转换成实体,比直接用反射快了不少.主要是首行转换的时候动态生成了委托. 后面的转换都是直接调 ...

  3. c# ef 排序字段动态,构建动态Lambda和扩展方法OrderBy

    1.动态构建排序 Lambda /// <summary> /// 获取排序Lambda(如果动态排序,类型不同会导致转换失败) /// </summary> /// < ...

  4. EntityFramework使用动态Lambda表达式筛选数据

    public static class PredicateBuilder { public static Expression<Func<T, bool>> True<T ...

  5. 动态LINQ(Lambda表达式)构建

    using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; us ...

  6. 动态生成C# Lambda表达式

    转载:http://www.educity.cn/develop/1407905.html,并整理! 对于C# Lambda的理解我们在之前的文章中已经讲述过了,那么作为Delegate的进化使用,为 ...

  7. Lambda表达式树构建(上)

    概述 Lambda是C#常用的语句,采用委托等方式,来封装真实的代码块.Lambda其实就是语法糖,是一个匿名函数,是一种高效的类似于函数式编程的表达式,Lambda简化了开发中需要编写的代码量.它可 ...

  8. 动态Lambda表达式打印HelloWorld

    最近在用C#与数据库打交道.开发过程中采用了ORM模型(以前是纯sql玩法,复杂的逻辑用存储过程做). 为了能通过配置文件动态地查询字段,也就是说需要能这样写: db.AsQuery<T> ...

  9. C# Lambda 表达式学习之(三):动态构建类似于 c => c.Age == null || c.Age > 18 的表达式

    可能你还感兴趣: 1. C# Lambda 表达式学习之(一):得到一个类的字段(Field)或属性(Property)名,强类型得到 2. C# Lambda 表达式学习之(二):LambdaExp ...

随机推荐

  1. I2C总线协议

     1.I2C协议   2条双向串行线,一条数据线SDA,一条时钟线SCL.   SDA传输数据是大端传输,每次传输8bit,即一字节.   支持多主控(multimastering),任何时间点只能有 ...

  2. 03、矢量图形查询工具(Symbol Unicode)

    目前的软件开发中,很多地方都使用到了矢量图标,在 Metro app 的开发中,可以使用 Windows 系统图标(02.Universal app 中按钮图标使用 ),包括 Segoe UI Sym ...

  3. Logstash日志字段拆分grok

    参考和测试网站:http://grokdebug.herokuapp.com 例如:test-39.dev.abc-inc.com Mon Apr 24 13:53:58 CST 2017 2017- ...

  4. 这不是bug,而是语言特性

    分析编程语言缺陷的一种方法是把所有的缺陷归于3类:不该做的做了,该做的没做,该做但做得不合适. 在使用switch case时,如果使用缺省的 fall through,请一定在旁边注释,因为97%的 ...

  5. nyoj16矩形嵌套(第一道dp关于dag的题目)

    http://acm.nyist.net/JudgeOnline/problem.php?pid=16 题意:有n个矩形,每个矩形可以用a,b来描述,表示长和宽.矩形X(a,b)可以嵌套在矩形Y(c, ...

  6. 卖座网一处SQL注射(Http Referer sqlinjection)

    漏洞作者: 猪猪侠 漏洞详情 披露状态: 2015-01-13: 细节已通知厂商并且等待厂商处理中2015-01-14: 厂商已经确认,细节仅向厂商公开2015-01-24: 细节向核心白帽子及相关领 ...

  7. ExecuteNonQuery和ExecuteScalar的区别

    ExecuteNonQuery   针对 Connection 执行 SQL 语句并返回受影响的行数. 返回值 受影响的行数. 备注 您可以使用 ExecuteNonQuery 来执行目录操作(例如查 ...

  8. DRBD(Distributed Replicated Block Device) 分布式块设备复制 进行集群高可用方案

    DRBD是一个用软件实现的.无共享的.服务器之间镜像块设备内容的存储复制解决方案. 外文名 DRBD drbdadm 高级管理工具 drbdsetup 置装载进kernel的DRBD模块 drbdme ...

  9. C++ 类中的静态成员变量,静态成员函数

    //类中的静态成员变量,静态成员函数 #define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std; /* ...

  10. php ut8声明

    header("Content-type: text/html; charset=utf-8");