首页 > Python基础教程 >
-
C#教程之Orm框架开发之NewExpression合并问题
之前都是看别人写博客,自己没有写博客的习惯.在工作的过程中,总是会碰到许多的技术问题.有很多时候想记录下来,后面一直有许多的问题等着解决.总想着等系统完成了,再回头总结下.往往结果就把这事抛到脑后了.
总觉得不能一直这样哈.今天简单记一下吧.有表达不清楚的地方,多多包涵.
最近在研究.net orm框架.想开发一套更好用的Orm框架.别嫌轮子多.碰到一个Expression合并的问题.
一.需求情况描述
需要更新部分数据的时候,可能前端传回的只有部分字段的数据.而更新的时候,需要设置更新人,更新日期等.
举个栗子来说:
现在有一个预约信息表
前端需要修改数据内容如下,我们暂且叫表达A
var exp = ExpressionHelper.CreateExpression<AppointmentDto>(a => new {
a.Id,
a.PatientName,
a.PatientNamePy,
a.IdentityCardNumber,
a.Birthday,
a.PatientAge,
a.PatientSex,
a.PatientPhone,
a.Address
});
而写入数据库的时候需要添加更新人,更新时间.LastUpdateUserId和UpdateTime.
于是我们便又多了一个lambda表达式,我们叫它表达式B
var exp = ExpressionHelper.CreateExpression<AppointmentDto>(a => new {
a.Id,
a.PatientName,
a.PatientNamePy,
a.IdentityCardNumber,
a.Birthday,
a.PatientAge,
a.PatientSex,
a.PatientPhone,
a.Address,
a.LastUpdateUserId,
a.UpdateTime
});
这里说下ExpressionHelper.CreateExpression<T>方法,只是一个为了缩减代码长度而写的方法.输入的lambda表达式原样返回了.
外面不用写好长的类型了.Expression这个类型平时不用.写外面看着眼晕. Expression<Func<AppointmentDto, object>> exp1 = a => new {a.Id,a.PatientName};
/// <summary>
/// 转换Expr
/// 在外面调用时可以使用var以减少代码长度
/// </summary>
/// <param name="expr"></param>
/// <returns></returns>
public static Expression<Func<T, object>> CreateExpression<T>(Expression<Func<T, object>> expr)
{
return expr;
}
所以此处,使用var可以看起来更整洁.但并不推荐在正常情况下使用var.
个人觉得使用var让代码可维护性降低.读起来真的是头疼.之前在维护一个比较大的系统的时候,公司的主要项目,缺少项目文档,代码里面也基本上没啥注释.而且又清一色的var,每个方法返回的是啥类型?你得去方法那边看去.看着真是恼火,又不得不去一点一点的改.都改成相应的类型后,看着就清爽多了.看一眼,流程就基本上能明白大概.所以,var在C#这种强类型语言里,能不用就别用了.
上面就当是发牢骚了.我们回到正题.
我们看到表达式B比表达式A只多了两个字段.大多数代码都是重复的.而且,两个lambda表达式严重的加长了代码行数.几个这样的表达式下来,这个类就到了几百行了.
对于喜欢简洁,简单的我来说,类一大了我就头疼.那咋整?要是有办法将这两个表达式简化处理一下就好了.将表达式A加上一个短的表达式,来实现表达式B呢.
比如实现 var exprB = exprA.Add(a => new { a.PatientPhone });
So,开始捯饬...
二.解决方法
因为这个合并表达式的方法是在个人系统内部使用满足我定制的Orm的类名称需求
所以定义了一个新的Expression表达式类型NewObjectExpression来处理
待处理的属性都放到了Members里面.后面解析使用的也是Members.其它方法Copy自NewExpression的源码,可以删了不用.
下面我们来扩展Expression<Func<T, object>>,让Expression<Func<T, object>>拥有Add和Remove属性的方法.
直接上代码,看前两个方法.后面两个方法是扩展Expression<Func<T, bool>>表达式的And和Or.等有回头有空再介绍.
Add方法可处理 NewExpression 类似 t=>new{t.Id,t.Name} , UnaryExpression 类似t=>t.Id,以及我们自定义的NewObjectExpression类型
所以我们在更新数据的时候就可以这么写了:
Dbc.Db.Update(dto, exp.Add(a => a.LastUpdateUserId));
Dbc.Db.Update(dto, exp.Add(a => new { a.LastUpdateUserId, a.UpdateTime }));
在Orm框架内部,解析NewObjectExpression时,解析方法如下
至此,就完成了Expression<Func<T, object>>Add和Remove属性的扩展,Orm可以让代码更简洁.
三.后记
其实在使用新的类NewObjectExpression来解决之前,尝试过其它的许多方式,因为使用.net的类型可以在其它的框架程序中借鉴引用.不必局限在个人框架内部.
NewExpression内部有一些校验,本身Expression<Func<T, object>>是一个匿名类.试过处理NewExpression,以及新建类继承自NewExpression等方式.都没成功.
要是大家有更好的方法欢迎留言告知.希望本文能对大家有所帮助.