使用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,这种形 ...
随机推荐
- Python 设计模式之路
备注:本套笔记内容来源于互联网,只做学习使用,如有侵权请联系本笔记作者. 资料内容 Python 设计模式之路(一)——设计模式 初识 Python 设计模式之路(二)——简单工厂.工厂.抽象工厂模式 ...
- 京东Alpha平台开发笔记系列(二)
第一篇博文简单讲了一下京东Alpha平台与个人idea技能,本篇将讲解Alpha平台与个人开发需要的一些知识,下面开篇 ——>>> 上图就是京东Alpha技能平台的首页,Skill平 ...
- STM32CubeMX HAL库串口+DMA数据发送不定长度数据接收
参考资料:1.ST HAL库官网资料 2.https://blog.csdn.net/u014470361/article/details/79206352#comments 一.STM32CubeM ...
- String StringBuilder StringBuffer区别
String StringBuilder StringBuffer String类是final类,不可以被继承,且它的成员方法也是final方法,当一个字符串对象进行操作操作时,任何的改变不会影响到这 ...
- Exp2 后门原理与实践 20154320 李超
目录- 基础问题回答- 基础知识- 实验过程- 实验心得体会 基础知识问答 1. 例举你能想到的一个后门进入到你系统中的可能方式?从不安全的网站上下载的程序可能存在后门. 2. 例举你知道的后门如何启 ...
- Touch365现已上架!
欢迎体验由武宇亭.诸子轩.梁国伟.张裕浩.孔维喆.邱亚威同学开发的创意照片浏览软件Touch365,现已上架Microsoft官方商城! https://www.microsoft.com/zh-cn ...
- ubuntu installs matlab2017a
cd mkdir matlab sudo mount -o loop *1.iso matlab sudo ./matlab/install ... sudo mount -o loop *2.iso ...
- 为什么要使用CMake?
如果你曾经维护过软件包的构建和安装过程,你将对CMake感兴趣.CMake是软件项目的一个开源生成管理器,它允许开发人员以简单的可移植文本文件格式指定生成参数.然后,CMake 使用此文件为本机开发工 ...
- ios之好用的Reachability
#import <Foundation/Foundation.h> @interface NetWorkTool : NSObject + (instancetype)shareInsta ...
- Maven3-依赖
依赖配置 我们先来看一份简单的依赖声明: <project> ... <dependencies> <dependency> <groupId>...& ...