使用Asp.Net Core MVC 开发项目实践[第四篇:基于EF Core的扩展2]
上篇我们说到了基于EFCore的基础扩展,这篇我们讲解下基于实体结合拉姆达表达式的自定义更新以及删除数据.
先说下原理:其实通过实体以及拉姆达表达式生成SQL语句去执行
第一种更新扩展:
自定义更新字段以及自定义扩展条件,请看下面的代码
/// <summary> /// 自定义更新扩展 /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="context"></param> /// <param name="fields">更新字段</param> /// <param name="predicate">更新条件</param> /// <returns></returns> public static bool MangoUpdate<TEntity>(this DbContext context, Expression<Func<TEntity, bool>> fields, Expression<Func<TEntity, bool>> predicate) where TEntity : class, new() { TSqlAssembledResult result = TSqlAssembled.Update<TEntity>(fields, predicate); context.Database.ExecuteSqlCommand(result.SqlStr); ? true : false; }
从上面的方法中我们看到几个参数,第一个参数不必说,扩展方法第一个参数必须要的,我们重点讲清楚一下第二个和第三个参数.
参数:
Expression<Func<TEntity, bool>> fields
表示实体中需要更新的字段,这里的参数要求的是一个拉姆达表达式,如下面的代码:
m => m.ClickCount == m.ClickCount +
这里就是更新字段ClickCount+1的功能.
参数:
Expression<Func<TEntity, bool>> predicate
表示更新条件,这个参数也是一个拉姆达表达式,如下面代码:
m => m.NavigationId == navigationId
这里表示更新条件 NavigationId指定值的数据库记录.
接下来我们看方法中的调用
TSqlAssembled.Update<TEntity>(fields, predicate);
这个方法表示将参数解析成SQL语句,我们看看这个方法的具体内容:
/// <summary> /// 更新语句组装 /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="fields"></param> /// <param name="predicate"></param> /// <returns></returns> public static TSqlAssembledResult Update<TEntity>(Expression<Func<TEntity, bool>> fields, Expression<Func<TEntity, bool>> predicate) where TEntity : class, new() { try { StringBuilder strBuilder = new StringBuilder(); strBuilder.Append("update "); strBuilder.Append(typeof(TEntity).Name); strBuilder.Append(" set "); //解析需要更新的字段值 UpdateFieldBuilder updateFieldBuilder = new UpdateFieldBuilder(); strBuilder.Append(updateFieldBuilder.Translate(fields)); //解析条件 ConditionBuilder conditionBuilder = new ConditionBuilder(); strBuilder.Append(" where "); strBuilder.Append(conditionBuilder.Translate(predicate)); //处理结果返回 TSqlAssembledResult result = new TSqlAssembledResult(); result.SqlParameters = null; result.SqlStr = strBuilder.ToString(); return result; } catch(Exception ex) { return null; throw ex; } }
PS:这个方法中用到的条件编译类以及字段编辑类我们将在文章底部贴出来.
第二种更新扩展:
/// <summary> /// 自定义更新扩展 /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="context"></param> /// <param name="entity">更新实体</param> /// <param name="predicate">更新条件</param> /// <returns></returns> public static bool MangoUpdate<TEntity>(this DbContext context, TEntity entity, Expression<Func<TEntity, bool>> predicate) where TEntity:class,new() { TSqlAssembledResult result = TSqlAssembled.Update<TEntity>(entity, predicate); context.Database.ExecuteSqlCommand(result.SqlStr, result.SqlParameters); ? true : false; }
参数 TEntity entity表示需要更新的实体
参数 Expression<Func<TEntity, bool>> predicate 表示更新条件,示例如下:
m => m.NavigationId == navigationId
TSqlAssembled.Update<TEntity>(entity, predicate) 这个方法表示将参数解析成SQL语句,我们看看这个方法的具体内容:
/// <summary> /// 更新语句组装 /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="entity"></param> /// <param name="predicate"></param> /// <returns></returns> public static TSqlAssembledResult Update<TEntity>(TEntity entity, Expression<Func<TEntity, bool>> predicate) where TEntity : class, new() { try { StringBuilder strBuilder = new StringBuilder(); strBuilder.Append("update "); // Type type = entity.GetType(); strBuilder.Append(type.Name); strBuilder.Append(" set "); //处理实体类属性 PropertyInfo[] properties = type.GetProperties(); ; List<SqlParameter> sqlParameter = new List<SqlParameter>(); foreach (var property in properties) { object value = property.GetValue(entity, null); if (value != null) { ) { strBuilder.Append(","); } strBuilder.Append(property.Name); strBuilder.Append("=@"); strBuilder.Append(property.Name); sqlParameter.Add(new SqlParameter(property.Name, value)); index++; } } //编译条件 ConditionBuilder conditionBuilder = new ConditionBuilder(); strBuilder.Append(" where "); strBuilder.Append(conditionBuilder.Translate(predicate)); //处理结果返回 TSqlAssembledResult result = new TSqlAssembledResult(); result.SqlParameters = sqlParameter.ToArray(); result.SqlStr = strBuilder.ToString(); return result; } catch (Exception ex) { return null; throw ex; } }
PS:这里我们多了将实体反射获取需要更新的字段以及字段值.
第三种删除扩展:
自定删除条件,代码如下
/// <summary> /// 自定义删除扩展 /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="context"></param> /// <param name="predicate">删除条件</param> /// <returns></returns> public static bool MangoRemove<TEntity>(this DbContext context,Expression<Func<TEntity, bool>> predicate) where TEntity : class,new() { TSqlAssembledResult result = TSqlAssembled.Delete<TEntity>(predicate); context.Database.ExecuteSqlCommand(result.SqlStr); ? true : false; }
参数Expression<Func<TEntity, bool>> predicate表示为自定义条件,示例如下:
_dbContext.MangoRemove<Entity.m_PostsAnswerRecords>(m => m.AnswerId == model.AnswerId && m.UserId == model.UserId);
PS:此段代码表示根据指定条件删除m_PostsAnswerRecords表中的记录
TSqlAssembled.Delete<TEntity>(predicate)方法负责将指定条件编译成SQL语句,代码如下:
/// <summary> /// 删除语句组装 /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="predicate"></param> /// <returns></returns> public static TSqlAssembledResult Delete<TEntity>(Expression<Func<TEntity, bool>> predicate) where TEntity:class,new() { try { string tableName = typeof(TEntity).Name; //条件编译 ConditionBuilder conditionBuilder = new ConditionBuilder(); string conditionStr = conditionBuilder.Translate(predicate); StringBuilder strBuilder = new StringBuilder(); strBuilder.Append("delete from "); strBuilder.Append(tableName); strBuilder.Append(" where "); strBuilder.Append(conditionStr); //处理结果返回 TSqlAssembledResult result = new TSqlAssembledResult(); result.SqlParameters = null; result.SqlStr = strBuilder.ToString(); return result; } catch(Exception ex) { throw ex; } }
下面我们贴出字段以及条件的拉姆达表达式解析类:
条件解析类(ConditionBuilder):
using System; using System.Collections.Generic; using System.Text; using System.Linq; using System.Linq.Expressions; using System.Reflection; namespace Mango.Framework.EFCore { public class ConditionBuilder : ExpressionVisitor { StringBuilder strBuilder; public ConditionBuilder() { } public string Translate(Expression expression) { this.strBuilder = new StringBuilder(); this.Visit(expression); return this.strBuilder.ToString(); } private static Expression StripQuotes(Expression e) { while (e.NodeType == ExpressionType.Quote) { e = ((UnaryExpression)e).Operand; } return e; } protected override Expression VisitBinary(BinaryExpression b) { strBuilder.Append("("); this.Visit(b.Left); switch (b.NodeType) { case ExpressionType.AndAlso: strBuilder.Append(" and "); break; case ExpressionType.OrElse: strBuilder.Append(" or "); break; case ExpressionType.Equal: strBuilder.Append(" = "); break; case ExpressionType.NotEqual: strBuilder.Append(" <> "); break; case ExpressionType.LessThan: strBuilder.Append(" < "); break; case ExpressionType.LessThanOrEqual: strBuilder.Append(" <= "); break; case ExpressionType.GreaterThan: strBuilder.Append(" > "); break; case ExpressionType.GreaterThanOrEqual: strBuilder.Append(" >= "); break; default: throw new NotSupportedException(string.Format("运算符{0}不支持", b.NodeType)); } if (b.Right.NodeType != ExpressionType.Parameter&& b.Right.NodeType == ExpressionType.MemberAccess) { LambdaExpression lambda = Expression.Lambda(b.Right); var fn = lambda.Compile(); this.Visit(Expression.Constant(fn.DynamicInvoke(null), b.Right.Type)); } else { this.Visit(b.Right); } strBuilder.Append(")"); return b; } protected override Expression VisitConstant(ConstantExpression c) { switch (Type.GetTypeCode(c.Value.GetType())) { case TypeCode.Boolean: strBuilder.Append((( : ); break; case TypeCode.String: strBuilder.Append("'"); strBuilder.Append(c.Value); strBuilder.Append("'"); break; case TypeCode.Object: throw new NotSupportedException(string.Format("常量{0}不支持", c.Value)); default: strBuilder.Append(c.Value); break; } return c; } protected override Expression VisitMember(MemberExpression m) { if (m.Expression != null && m.Expression.NodeType == ExpressionType.Parameter) { strBuilder.Append(m.Member.Name); return m; } else if (m.Expression != null && m.Expression.NodeType == ExpressionType.Constant) { LambdaExpression lambda = Expression.Lambda(m); var fn = lambda.Compile(); this.Visit(Expression.Constant(fn.DynamicInvoke(null), m.Type)); return m; } throw new NotSupportedException(string.Format("成员{0}不支持", m.Member.Name)); } } }
更新字段解析类(UpdateFieldBuilder):
using System; using System.Collections.Generic; using System.Text; using System.Linq; using System.Linq.Expressions; using System.Reflection; namespace Mango.Framework.EFCore { public class UpdateFieldBuilder : ExpressionVisitor { StringBuilder strBuilder; public string Translate(Expression expression) { this.strBuilder = new StringBuilder(); this.Visit(expression); return this.strBuilder.ToString(); } private static Expression StripQuotes(Expression e) { while (e.NodeType == ExpressionType.Quote) { e = ((UnaryExpression)e).Operand; } return e; } protected override Expression VisitBinary(BinaryExpression b) { //strBuilder.Append("("); this.Visit(b.Left); switch (b.NodeType) { case ExpressionType.Equal: strBuilder.Append("="); break; case ExpressionType.AndAlso: strBuilder.Append(","); break; case ExpressionType.Add: strBuilder.Append("+"); break; case ExpressionType.Subtract: strBuilder.Append("-"); break; default: throw new NotSupportedException(string.Format("运算符{0}不支持", b.NodeType)); } this.Visit(b.Right); //strBuilder.Append(")"); return b; } protected override Expression VisitConstant(ConstantExpression c) { switch (Type.GetTypeCode(c.Value.GetType())) { case TypeCode.Boolean: strBuilder.Append((( : ); break; case TypeCode.String: strBuilder.Append("'"); strBuilder.Append(c.Value); strBuilder.Append("'"); break; case TypeCode.Object: throw new NotSupportedException(string.Format("常量{0}不支持", c.Value)); default: strBuilder.Append(c.Value); break; } return c; } protected override Expression VisitMember(MemberExpression m) { if (m.Expression != null && m.Expression.NodeType == ExpressionType.Parameter) { strBuilder.Append(m.Member.Name); return m; } throw new NotSupportedException(string.Format("成员{0}不支持", m.Member.Name)); } } }
到此本篇章完成,更详细的代码请下载源代码查看.
使用Asp.Net Core MVC 开发项目实践[第四篇:基于EF Core的扩展2]的更多相关文章
- 使用Asp.Net Core MVC 开发项目实践[第三篇:基于EF Core的扩展]
上篇我们说到了EFCore的基础使用,这篇我们将讲解下基于EFCore的扩展. 我们在Mango.Framework.EFCore类库项目中创建一个类名EFExtended的扩展类,并且引入相关的命名 ...
- 使用Asp.Net Core MVC 开发项目实践[第五篇:缓存的使用]
项目中我们常常会碰到一些数据,需要高频率用到但是又不会频繁变动的这类,我们就可以使用缓存把这些数据缓存起来(比如说本项目的导航数据,帖子频道数据). 我们项目中常用到有Asp.Net Core 本身提 ...
- 使用Asp.Net Core MVC 开发项目实践[第一篇:项目结构说明]
先从下图看整体项目结构: Mango.Manager: 为后台管理项目 Mango.Web: 为前台项目 Mango.Framework.Core: 为常用的基础操作类项目 Mango.Framewo ...
- 使用Asp.Net Core MVC 开发项目实践[第二篇:EF Core]
在项目中使用EF Core还是比较容易的,在这里我们使用的版本是EF Core 2.2. 1.使用nuget获取EF Core包 这个示例项目使用的是SQLSERVER,所以还需要下载Microsof ...
- 《ASP.NET Core应用开发入门教程》与《ASP.NET Core 应用开发项目实战》正式出版
“全书之写印,实系初稿.有时公私琐务猬集,每写一句,三搁其笔:有时兴会淋漓,走笔疾书,絮絮不休:有时意趣萧索,执笔木坐,草草而止.每写一段,自助覆阅,辄摇其首,觉有大不妥者,即贴补重书,故剪刀浆糊乃不 ...
- ASP.NET Core Web开发学习笔记-1介绍篇
ASP.NET Core Web开发学习笔记-1介绍篇 给大家说声报歉,从2012年个人情感破裂的那一天,本人的51CTO,CnBlogs,Csdn,QQ,Weboo就再也没有更新过.踏实的生活(曾辞 ...
- Asp.Net Core 2.0 项目实战(10) 基于cookie登录授权认证并实现前台会员、后台管理员同时登录
1.登录的实现 登录功能实现起来有哪些常用的方式,大家首先想到的肯定是cookie或session或cookie+session,当然还有其他模式,今天主要探讨一下在Asp.net core 2.0下 ...
- Asp.Net Core 2.0 项目实战(11) 基于OnActionExecuting全局过滤器,页面操作权限过滤控制到按钮级
1.权限管理 权限管理的基本定义:百度百科. 基于<Asp.Net Core 2.0 项目实战(10) 基于cookie登录授权认证并实现前台会员.后台管理员同时登录>我们做过了登录认证, ...
- C# 嵌入dll 动软代码生成器基础使用 系统缓存全解析 .NET开发中的事务处理大比拼 C#之数据类型学习 【基于EF Core的Code First模式的DotNetCore快速开发框架】完成对DB First代码生成的支持 基于EF Core的Code First模式的DotNetCore快速开发框架 【懒人有道】在asp.net core中实现程序集注入
C# 嵌入dll 在很多时候我们在生成C#exe文件时,如果在工程里调用了dll文件时,那么如果不加以处理的话在生成的exe文件运行时需要连同这个dll一起转移,相比于一个单独干净的exe,这种形 ...
随机推荐
- ModelAndView返回json对象的方法
这是在spring4之后. @RequestMapping(value = "/returnjson") public ModelAndView getfsd(){ ModelAn ...
- MySQL下创建数据库以及授权用户
一.新建数据库 1.首先登录MySQL:(输入 mysql -u root -p 命令,然后输入密码按回车即可) 2.在mysql> 下输入如下命令,回车,即可创建数据库 (test为数据库名) ...
- st表(poj3264)
st表很像线段树,但线段树既能查询和修改,而st表只能查询. 首先我们先用二维数组建立一个表,st[i][j]表内存的是从第i位开始1<<j范围内的best(st[i][j-1],st[i ...
- FPGA跨时钟域握手信号的结构
FPGA跨时钟数据传输,是我们经常遇到的问题的,下面给出一种跨时钟握手操作的电路结构.先上图 先对与其他人的结构,这个结构最大的特点是使用 req 从低到高或者高到低的变化 来表示DIN数据有效并开始 ...
- 一、Java和JavaScript
JavaScript诞生于1995年,所以他得叫我一声姐姐,(*^__^*) .当时它的主要任务就是表单验证,在还没JavaScript的时候,进行表单验证的时候必须要把数据提交到服务器,才能进行表单 ...
- 大叔学ML第四:线性回归正则化
目录 基本形式 梯度下降法中应用正则化项 正规方程中应用正则化项 小试牛刀 调用类库 扩展 正则:正则是一个汉语词汇,拼音为zhèng zé,基本意思是正其礼仪法则:正规:常规:正宗等.出自<楚 ...
- 【ISC安全训练营】挑战价格极限第三天!!![北京]
每到周三都觉得离周末不远啦,人生都充满的了希望,同样的,今天的优惠福利依旧超级给力,错过了可就没有了哦! 周三福利 名额 周四福利 名额 周五福利 名额 3折购买任意课程资格 3名 4折购买任意课程资 ...
- JSTL标签库的基本教程之核心标签库(二)
JSTL标签库的基本教程之核心标签库(二) 核心标签库 标签 描述 <c:out> 用于在JSP中显示数据,就像<%= ... > <c:set> 用于保存数据 & ...
- 吴恩达机器学习笔记44-核函数(Kernels)
回顾我们之前讨论过可以使用高级数的多项式模型来解决无法用直线进行分隔的分类问题: 为了获得上图所示的判定边界,我们的模型可能是
- 解决微信小程序登录与发布的一些问题
解决微信小程序的问题 图片在电脑上显示但在手机上却无法显示的问题 要使用的是本地图片,不想把图片上传到网络再通过https的方式解决,解决方法如下: 1.image src中的图片地址对英文字母大小写 ...