使用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,这种形 ...
随机推荐
- C++ Thrift服务端记录调用者IP和被调接口方法
Apache开源的Thrift(http://thrift.apache.org)有着广泛的使用,有时候需要知道谁调用了指定的函数,比如在下线一起老的接口之前,需要确保对这些老接口的访问已全部迁移到新 ...
- Python数据结构之单链表
Python数据结构之单链表 单链表有后继结点,无前继结点. 以下实现: 创建单链表 打印单链表 获取单链表的长度 判断单链表是否为空 在单链表后插入数据 获取单链表指定位置的数据 获取单链表指定元素 ...
- 扁平化promise调用链(译)
这是对Flattened Promise Chains的翻译,水平有限请见谅^ ^. Promises对于解决复杂异步请求与响应问题堪称伟大.AngularJS提供了$q和$http来实现它:还有很多 ...
- 【洛谷P2584】【ZJOI2006】GameZ游戏排名系统题解
[洛谷P2584][ZJOI2006]GameZ游戏排名系统题解 题目链接 题意: GameZ为他们最新推出的游戏开通了一个网站.世界各地的玩家都可以将自己的游戏得分上传到网站上.这样就可以看到自己在 ...
- 【UOJ117】 欧拉回路(欧拉回路)
传送门 UOJ Solution 无解 t=1,无向图,当且仅当\(\exists i \ \ in_i \ne out_i\) t=2,有向图,当且仅当\(\exists i \ \ in_i是奇数 ...
- 小程序上传wx.uploadFile - 小程序请假
小程序上传wx.uploadFile UploadTask wx.uploadFile(Object object) 将本地资源上传到服务器.客户端发起一个 HTTPS POST 请求,其中 cont ...
- Python学习笔记【第八篇】:Python内置模块
什么时模块 Python中的模块其实就是XXX.py 文件 模块分类 Python内置模块(标准库) 自定义模块 第三方模块 使用方法 import 模块名 form 模块名 import 方法名 说 ...
- soundJs库简单使用心得
概述 由于工作需要,学习了一下soundJs库,把心得记录下来,供以后开发时参考,相信对其他人也有用. soundJs是createJs的一部分,它提供了强大的API来处理音频,是音频类H5的一个比较 ...
- Metasploit Framework(8)后渗透测试(一)
文章的格式也许不是很好看,也没有什么合理的顺序 完全是想到什么写一些什么,但各个方面都涵盖到了 能耐下心看的朋友欢迎一起学习,大牛和杠精们请绕道 使用场景: Kali机器IP:192.168.163. ...
- 再谈spring的循环依赖是怎么造成的?
老生常谈,循环依赖!顾名思义嘛,就是你依赖我,我依赖你,然后就造成了循环依赖了!由于A中注入B,B中注入A导致的吗? 看起来没毛病,然而,却没有说清楚问题!甚至会让你觉得你是不清楚spring的循环依 ...