当前位置: 移动技术网 > IT编程>开发语言>.net > Orm框架开发之NewExpression合并问题

Orm框架开发之NewExpression合并问题

2019年01月10日  | 移动技术网IT编程  | 我要评论

贴小广告,天庭剩女全文阅读,山河恋全集剧情介绍

之前都是看别人写博客,自己没有写博客的习惯.在工作的过程中,总是会碰到许多的技术问题.有很多时候想记录下来,后面一直有许多的问题等着解决.总想着等系统完成了,再回头总结下.往往结果就把这事抛到脑后了.

总觉得不能一直这样哈.今天简单记一下吧.有表达不清楚的地方,多多包涵.

最近在研究.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来处理

  1     /// <summary>
  2     /// new object expression
  3     /// 合并newexpression使用.
  4     /// </summary>
  5     public class newobjectexpression : expression, iargumentprovider
  6     {
  7         private ilist<expression> arguments;
  8 
  9         /// <summary>
 10         /// 构造方法
 11         /// </summary>
 12         /// <param name="constructor"></param>
 13         /// <param name="arguments"></param>
 14         /// <param name="members"></param>
 15         internal newobjectexpression(constructorinfo constructor, ilist<expression> arguments, list<memberinfo> members)
 16         {
 17             this.constructor = constructor;
 18             this.arguments = arguments;
 19             this.members = members;
 20 
 21             if (members != null)
 22             {
 23                 list<string> namelist = members.select(member => member.name).tolist();
 24                 for (int i = 0; i < namelist.count; i++)
 25                 {
 26                     if (!string.isnullorempty(expressionstring))
 27                     {
 28                         expressionstring += "," + namelist[i];
 29                     }
 30                     else
 31                     {
 32                         expressionstring = namelist[i];
 33                     }
 34                 }
 35             }
 36         }
 37 
 38         /// <summary>
 39         /// gets the static type of the expression that this <see cref="expression" /> represents. (inherited from <see cref="expression"/>.)
 40         /// </summary>
 41         /// <returns>the <see cref="type"/> that represents the static type of the expression.</returns>
 42         public override type type
 43         {
 44             get { return constructor.declaringtype; }
 45         }
 46 
 47         /// <summary>
 48         /// returns the node type of this <see cref="expression" />. (inherited from <see cref="expression" />.)
 49         /// </summary>
 50         /// <returns>the <see cref="expressiontype"/> that represents this expression.</returns>
 51         public sealed override expressiontype nodetype
 52         {
 53             get { return expressiontype.new; }
 54         }
 55 
 56         /// <summary>
 57         /// gets the called constructor.
 58         /// </summary>
 59         public constructorinfo constructor { get; }
 60 
 61         /// <summary>
 62         /// gets the arguments to the constructor.
 63         /// </summary>
 64         public readonlycollection<expression> arguments
 65         {
 66             get { return (readonlycollection<expression>)arguments; }
 67         }
 68 
 69         expression iargumentprovider.getargument(int index)
 70         {
 71             return arguments[index];
 72         }
 73 
 74         int iargumentprovider.argumentcount
 75         {
 76             get
 77             {
 78                 return arguments.count;
 79             }
 80         }
 81         
 82         /// <summary>
 83         /// expressionstring
 84         /// </summary>
 85         public string expressionstring { get; private set; } = "";
 86 
 87         public constructorinfo constructor1 => constructor;
 88 
 89         public list<memberinfo> members { get; set; }
 90 
 91         /// <summary>
 92         /// 更新members
 93         /// </summary>
 94         /// <param name="arguments"></param>
 95         /// <param name="members"></param>
 96         /// <returns></returns>
 97         public newobjectexpression update(ilist<expression> arguments, list<memberinfo> members)
 98         {
 99             if (arguments != null)
100             {
101                 this.arguments = arguments;
102             }
103             if (members != null)
104             {
105                 this.members = members;
106                 expressionstring = "";
107                 list<string> namelist = members.select(member => member.name).tolist();
108                 for (int i = 0; i < namelist.count; i++)
109                 {
110                     if (!string.isnullorempty(expressionstring))
111                     {
112                         expressionstring += "," + namelist[i];
113                     }
114                     else
115                     {
116                         expressionstring = namelist[i];
117                     }
118                 }                
119             }
120             return this;
121         }
122     }
view code

待处理的属性都放到了members里面.后面解析使用的也是members.其它方法copy自newexpression的源码,可以删了不用.

下面我们来扩展expression<func<t, object>>,让expression<func<t, object>>拥有add和remove属性的方法.

直接上代码,看前两个方法.后面两个方法是扩展expression<func<t, bool>>表达式的and和or.等有回头有空再介绍.

  1     /// <summary>
  2     /// expression 扩展
  3     /// </summary>
  4     public static class expressionexpand
  5     {
  6         /// <summary>
  7         /// expression and 
  8         /// newexpression 合并
  9         /// </summary>
 10         /// <param name="expr"></param>
 11         /// <returns></returns>
 12         public static expression<func<t, object>> add<t>(this expression<func<t, object>> expr, expression<func<t, object>> expandexpr)
 13         {
 14             expression<func<t, object>> result = null;
 15             parameterexpression parameter = expression.parameter(typeof(t), "p");
 16             list<memberinfo> memberinfolist = new list<memberinfo>();
 17             #region 处理原expr
 18             if (expr.body is newexpression)
 19             {   // t=>new{t.id,t.name}
 20                 newexpression newexp = expr.body as newexpression;
 21                 if (newexp.members != null)
 22                 {
 23                     memberinfolist = newexp.members.tolist();
 24                 }
 25             }
 26             else if (expr.body is newobjectexpression)
 27             {
 28                 newobjectexpression newexp = expr.body as newobjectexpression;
 29                 if (newexp.members != null)
 30                 {
 31                     memberinfolist = newexp.members.tolist();
 32                 }
 33             }
 34             else if (expr.body is unaryexpression)
 35             {   //t=>t.id
 36                 unaryexpression unaryexpression = expr.body as unaryexpression;
 37                 memberexpression memberexp = unaryexpression.operand as memberexpression;
 38                 memberinfolist.add(memberexp.member);
 39             }
 40             #endregion
 41 
 42             #region 处理扩展expr
 43             if (expandexpr.body is newexpression)
 44             {   // t=>new{t.id,t.name}
 45                 newexpression newexp = expandexpr.body as newexpression;
 46                 for (int i = 0; i < newexp.members.count; i++)
 47                 {
 48                     memberexpression memberexp = expression.property(parameter, newexp.members[i].name);
 49                     if (!memberinfolist.any(member => member.name == newexp.members[i].name))
 50                     {
 51                         memberinfolist.add(newexp.members[i]);
 52                     }
 53                 }
 54             }
 55             else if (expr.body is newobjectexpression)
 56             {
 57                 newobjectexpression newexp = expr.body as newobjectexpression;
 58                 if (newexp.members != null && newexp.members.count > 0)
 59                 {
 60                     for (int i = 0; i < newexp.members.count; i++)
 61                     {
 62                         memberexpression memberexp = expression.property(parameter, newexp.members[i].name);
 63                         if (!memberinfolist.any(member => member.name == newexp.members[i].name))
 64                         {
 65                             memberinfolist.add(newexp.members[i]);
 66                         }
 67                     }
 68                 }
 69             }
 70             else if (expandexpr.body is unaryexpression)
 71             {   //t=>t.id
 72                 unaryexpression unaryexpression = expandexpr.body as unaryexpression;
 73                 memberexpression memberexp = unaryexpression.operand as memberexpression;
 74                 if (!memberinfolist.any(exp => exp.name == memberexp.member.name))
 75                 {
 76                     memberinfolist.add(memberexp.member);
 77                 }
 78             }
 79             #endregion
 80             newobjectexpression newobjexpression = new newobjectexpression(typeof(object).getconstructors()[0], null, memberinfolist);
 81             result = expression.lambda<func<t, object>>(newobjexpression, parameter);
 82             return result;
 83         }
 84 
 85         /// <summary>
 86         /// expression remove 
 87         /// newexpression 合并
 88         /// </summary>
 89         /// <param name="expr"></param>
 90         /// <returns></returns>
 91         public static expression<func<t, object>> remove<t>(this expression<func<t, object>> expr, expression<func<t, object>> expandexpr)
 92         {
 93             expression<func<t, object>> result = null;
 94             parameterexpression parameter = expression.parameter(typeof(t), "p");
 95             list<memberinfo> memberinfolist = new list<memberinfo>();
 96             list<memberinfo> removememberinfolist = new list<memberinfo>();
 97             #region 处理原expr
 98             if (expr.body is newexpression)
 99             {   // t=>new{t.id,t.name}
100                 newexpression newexp = expr.body as newexpression;
101                 if (newexp.members != null)
102                 {
103                     memberinfolist = newexp.members.tolist();
104                 }
105             }
106             else if (expr.body is newobjectexpression)
107             {
108                 newobjectexpression newexp = expr.body as newobjectexpression;
109                 if (newexp.members != null)
110                 {
111                     memberinfolist = newexp.members.tolist();
112                 }
113             }
114             else if (expr.body is unaryexpression)
115             {   //t=>t.id
116                 unaryexpression unaryexpression = expr.body as unaryexpression;
117                 memberexpression memberexp = unaryexpression.operand as memberexpression;
118                 memberinfolist.add(memberexp.member);
119             }
120             #endregion
121 
122             #region 处理扩展expr
123             if (expandexpr.body is newexpression)
124             {   // t=>new{t.id,t.name}
125                 newexpression newexp = expandexpr.body as newexpression;
126                 for (int i = 0; i < newexp.members.count; i++)
127                 {
128                     memberexpression memberexp = expression.property(parameter, newexp.members[i].name);
129                     if (!removememberinfolist.any(member => member.name == newexp.members[i].name))
130                     {
131                         removememberinfolist.add(newexp.members[i]);
132                     }
133                 }
134             }
135             else if (expr.body is newobjectexpression)
136             {
137                 newobjectexpression newexp = expr.body as newobjectexpression;
138                 if (newexp.members != null && newexp.members.count > 0)
139                 {
140                     for (int i = 0; i < newexp.members.count; i++)
141                     {
142                         memberexpression memberexp = expression.property(parameter, newexp.members[i].name);
143                         if (!removememberinfolist.any(member => member.name == newexp.members[i].name))
144                         {
145                             removememberinfolist.add(newexp.members[i]);
146                         }
147                     }
148                 }
149             }
150             else if (expandexpr.body is unaryexpression)
151             {   //t=>t.id
152                 unaryexpression unaryexpression = expandexpr.body as unaryexpression;
153                 memberexpression memberexp = unaryexpression.operand as memberexpression;
154                 if (!memberinfolist.any(exp => exp.name == memberexp.member.name))
155                 {
156                     removememberinfolist.add(memberexp.member);
157                 }
158             }
159             #endregion
160 
161             for (int i = memberinfolist.count - 1; i >= 0; i--)
162             {
163                 if (removememberinfolist.any(member => member.name == memberinfolist[i].name))
164                 {
165                     memberinfolist.remove(memberinfolist[i]);
166                 }
167             }
168             if (memberinfolist.count <= 0)
169             {
170                 throw new system.exception("expression remove error.all properties are removed.");
171             }
172             newobjectexpression newobjexpression = new newobjectexpression(typeof(object).getconstructors()[0], null, memberinfolist);
173             result = expression.lambda<func<t, object>>(newobjexpression, parameter);
174             return result;
175         }
176 
177         /// <summary>
178         /// expression and
179         /// </summary>
180         /// <param name="expr"></param>
181         /// <returns></returns>
182         public static expression<func<t, bool>> and<t>(this expression<func<t, bool>> expr, expression<func<t, bool>> expandexpr)
183         {
184             expression<func<t, bool>> result = expression.lambda<func<t, bool>>(expression.and(expandexpr.body, expr.body), expr.parameters);
185             return result;
186         }
187 
188         /// <summary>
189         /// expression and
190         /// </summary>
191         /// <param name="expr"></param>
192         /// <returns></returns>
193         public static expression<func<t, bool>> or<t>(this expression<func<t, bool>> expr, expression<func<t, bool>> expandexpr)
194         {
195             expression<func<t, bool>> result = expression.lambda<func<t, bool>>(expression.or(expandexpr.body, expr.body), expr.parameters);
196             return result;
197         }
198     }
view code

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时,解析方法如下

 1         /// <summary>
 2         /// 通过lambed expression获取属性名称
 3         /// </summary>
 4         /// <param name="expr">查询表达式</param>
 5         /// <returns></returns>
 6         public static list<string> getpilist<t>(expression<func<t, object>> expr)
 7         {
 8             list<string> result = new list<string>();
 9             if (expr.body is newexpression)
10             {   // t=>new{t.id,t.name}
11                 newexpression nexp = expr.body as newexpression;
12                 if (nexp.members != null)
13                 {
14                     result = nexp.members.select(member => member.name).tolist();
15                 }
16             }
17             else if (expr.body is newobjectexpression)
18             {   // t=>new{t.id,t.name}
19                 newobjectexpression nexp = expr.body as newobjectexpression;
20                 if (nexp.members != null)
21                 {
22                     result = nexp.members.select(member => member.name).tolist();
23                 }
24             }
25             else if (expr.body is unaryexpression)
26             {   //t=>t.id
27                 unaryexpression uexp = expr.body as unaryexpression;
28                 memberexpression mexp = uexp.operand as memberexpression;
29                 result.add(mexp.member.name);
30             }
31             else
32             {
33                 throw new system.exception("不支持的select lambda写法");
34             }
35             return result;
36         }
view code

至此,就完成了expression<func<t, object>>add和remove属性的扩展,orm可以让代码更简洁.

三.后记

其实在使用新的类newobjectexpression来解决之前,尝试过其它的许多方式,因为使用.net的类型可以在其它的框架程序中借鉴引用.不必局限在个人框架内部.

newexpression内部有一些校验,本身expression<func<t, object>>是一个匿名类.试过处理newexpression,以及新建类继承自newexpression等方式.都没成功.

要是大家有更好的方法欢迎留言告知.希望本文能对大家有所帮助.

 

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网