做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. windows 添加打印机

    控制面板---->硬件和声音---->设备和打印机--->点击添加打印机 最后安驱动(选择通用) OK!

  2. Tomcat7中开启gzip压缩功能的配置方法

    使用gzip压缩可以减少数据传输大小,加快网页加载速度.很多大站都开启了gzip压缩,不过也有很多网站并没有开启gzip压缩,上次看了一篇文章说开启gzip压缩后对搜索引擎不友好,但从带宽和流量的角度 ...

  3. 每日英语:The Perils Of Giving Advice

    I know what you should do and here's my advice. How many times have you heard that (and groaned)? gr ...

  4. iOS状态栏标志

    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; //显示 [UIApplication sharedA ...

  5. phoenix系统创建语句

    CREATE TABLE SYSTEM."CATALOG"( TENANT_ID VARCHAR NULL, TABLE_SCHEM VARCHAR NULL, TABLE_NAM ...

  6. JS学习笔记(1)--sort排序

    sort() 方法用于对数组的元素进行排序. 请注意,数组在原数组上进行排序,不生成副本. 说明 如果调用该方法时没有使用参数,将按字母顺序对数组中的元素进行排序,说得更精确点,是按照字符编码的顺序进 ...

  7. 简单实现Spring中BeanFactory原理

    上一篇文章介绍了Java反射机制在Spring IOC中的应用,知道了BeanFactory底层的实现原理. 原理搞懂了,对Spring IOC理解起来也很容易. 先来看看Java代码获取Spring ...

  8. REST学习

    RPC架构与REST架构 RPC:RPC将服务器看作一些列动作的集合(需要做某件事) REST:将服务器看作分布式对象集合,客户端通过调用这些对象上的方法来执行特定的任务,组件交互的可伸缩性.接口的通 ...

  9. 如何让jquery-easyui的combobox像select那样不可编辑

    http://zhidao.baidu.com/link?url=td61iIn_MBCs1FvT7b-B9Lp9VzlyrcnGmSbkCy1EsSzuod5o47zTmJFRQ-xizxdqv1E ...

  10. JS侦测设备旋转方向

    window.onload = window.onresize = function initialLoad(){updateOrientation();} function updateOrient ...