使用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,这种形 ...
随机推荐
- 生成图形化html报告
生成图形化html报告: 1.从cmd 进入执行测试文件 2.执行该命令:jmeter -n -t <test JMX file> -l <test log file> -e ...
- 海龟绘图turtle库之二级基础编程题
一.画一个太极图 import turtle as t t.pensize(2)#设置笔画宽度 t.circle(100)#以100为半径的圆 t.circle(50, 180) t.circle(- ...
- MVC+EF 多条件查询
根据以前的做法是拼接sql语句,这会增加维护成本,因为sql语句里的内容不会报错,所以在使用ef的时候必须要抛弃拼接sql语句的习惯. 构建实例 List<vyw_user> list = ...
- hightopo自己用开源的方案重构一遍
经过一年多的学习吧前面路上的坑基本算踩过一遍了 所以下面计划吧hightopo网站上的demo用自己的方式重新写一遍
- BiggerInteger类
java.math.BigInteger(需要导包)1.BigInteger构造方法*public BigInteger(String val)将 BigInteger 的十进制字符串表示形式转换为 ...
- 把纯C的动态库代码改造成C++版的
近期想把一份纯C的跨Win/Linux的动态库工程代码改成支持C++编译器,这样用C++写起代码来比较顺手.要点是保证动态库的ABI一致性,既导出接口不能改变. 主要的改动有: 1.把.c后缀名换成. ...
- Web browser的发展演变
我们每天都在使用着浏览器,每个人使用的浏览器各不一样.在这个科技飞速发展的时代,一个游览器能否站住脚跟取决于使用者的数量,看用户是否喜欢这个产品,听取用户们的意见来改善. 我们这个年龄的人最初用到的浏 ...
- 关于C++用法的学习心得
通过大一一学期对C++语言的学习,我感觉c++是一门有一定难度并且很有挑战性的科目,在c++学习过程中,我们懂得了其有很多的用法. 引用是C++引入的新语言特性,是C++常用的一个重要内容之一,正确. ...
- 深入理解JVM(一)——基本原理
前言 JVM一直是java知识里面进阶阶段的重要部分,如果希望在java领域研究的更深入,则JVM则是如论如何也避开不了的话题,本系列试图通过简洁易读的方式,讲解JVM必要的知识点. 运行流程 我们都 ...
- SpringBoot 通过 Exploded Archives 的方式部署
之前部署 SpringBoot 一直是用可执行 jar 的方式. java -jar codergroup-1.0.0.jar 就可以启动项目,为了能在后台运行,通常我们会使用这行命令 nohup j ...