EFCore扩展Update方法(实现 Update User SET Id=Id+1)
EFCore扩展Update方法(实现 Update User SET Id = Id + 1)
前言
- EFCore在操作更新的时候往往需要先查询一遍数据,再去更新相应的字段,如果针对批量更新的话会很麻烦,效率也很低。
- 目前github上 EFCore.Extentions 项目,实现批量更新挺方便的,但是针对 Update User SET Id = Id + 1 这种操作还是没有解决
- 本文主要就是扩展自更新Update
实现原理
- 先根据IQuaryable 获取到SQL语句
private static readonly FieldInfo QueryCompilerField = typeof(EntityQueryProvider).GetTypeInfo().DeclaredFields.First(x => x.Name == "_queryCompiler");
private static readonly FieldInfo QueryModelGeneratorField = QueryCompilerTypeInfo.DeclaredFields.First(x => x.Name == "_queryModelGenerator");
private static readonly FieldInfo DataBaseField = QueryCompilerTypeInfo.DeclaredFields.Single(x => x.Name == "_database");
private static readonly PropertyInfo DatabaseDependenciesField = typeof(Database).GetTypeInfo().DeclaredProperties.Single(x => x.Name == "Dependencies");
/// <summary>
/// 将query 转化为sql语句
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="query"></param>
/// <returns></returns>
internal static string ToSql<TEntity>(this IQueryable<TEntity> query) where TEntity : class
{
var queryCompiler = (QueryCompiler)QueryCompilerField.GetValue(query.Provider);
var modelGenerator = (QueryModelGenerator)QueryModelGeneratorField.GetValue(queryCompiler);
var queryModel = modelGenerator.ParseQuery(query.Expression);
var database = (IDatabase)DataBaseField.GetValue(queryCompiler);
var databaseDependencies = (DatabaseDependencies)DatabaseDependenciesField.GetValue(database);
var queryCompilationContext = databaseDependencies.QueryCompilationContextFactory.Create(false);
var modelVisitor = (RelationalQueryModelVisitor)queryCompilationContext.CreateQueryModelVisitor();
modelVisitor.CreateQueryExecutor<TEntity>(queryModel);
string sql = modelVisitor.Queries.First().ToString();
return sql;
}
- 把获取的查询语句的,From之前的语句砍掉,然后拼接
{
string sqlQuery = query.ToSql();
string tableAlias = sqlQuery.Substring(8, sqlQuery.IndexOf("]") - 8);
int indexFROM = sqlQuery.IndexOf(Environment.NewLine);
string sql = sqlQuery.Substring(indexFROM, sqlQuery.Length - indexFROM);
sql = sql.Contains("{") ? sql.Replace("{", "{{") : sql; // Curly brackets have to escaped:
sql = sql.Contains("}") ? sql.Replace("}", "}}") : sql; // https://github.com/aspnet/EntityFrameworkCore/issues/8820
return (sql, tableAlias);
}
- 根据传入的表达式Expression<Func<T,bool> 生成(Update [a] SET) 之后要更新的部分.列如:Expression<Func<T,bool> expression=a=>a.Id == a.Id + 1 生成[a].[Id]=[a].[Id]+parm_0 pram_0=1
通过分析Expression的节点[NodeType]来生成相应的操作符,递归拼接sql语句和参数
{
if (expression is BinaryExpression binaryExpression)
{
CreateUpdateBody(Param, binaryExpression.Left, ref sb, ref sp);
switch (binaryExpression.NodeType)
{
case ExpressionType.Add:
sb.Append(" +");
break;
case ExpressionType.Divide:
sb.Append(" /");
break;
case ExpressionType.Multiply:
sb.Append(" *");
break;
case ExpressionType.Subtract:
sb.Append(" -");
break;
case ExpressionType.And:
sb.Append(" ,");
break;
case ExpressionType.AndAlso:
sb.Append(" ,");
break;
case ExpressionType.Or:
sb.Append(" ,");
break;
case ExpressionType.OrElse:
sb.Append(" ,");
break;
case ExpressionType.Equal:
sb.Append(" =");
break;
default: break;
}
CreateUpdateBody(Param, binaryExpression.Right, ref sb, ref sp);
}
if (expression is ConstantExpression constantExpression)
{
var parmName = $"param_{sp.Count}";
sp.Add(new SqlParameter(parmName, constantExpression.Value));
sb.Append($" @{parmName}");
}
if (expression is MemberExpression memberExpression)
{
sb.Append($"{Param}.[{memberExpression.Member.Name}]");
}
}
最后执行生成SQL语句,详情请看源码github
调用
{
using (var context = new TestContext())
{
var list = context.User.Select<UserModel>().ToList();
var user1 = context.User.AsNoTracking().FirstOrDefault(x => x.Id == 2);
Console.WriteLine($"-----------Before Update --------------------");
Console.WriteLine($"{user1.Id}:{user1.Name}:{user1.RoleId}");
context.User.Where(x => x.Id == 2).RestValue(x => x.Name == (x.Name + " Add Bob") && x.RoleId == (x.RoleId + 1));
var user2 = context.User.AsNoTracking().FirstOrDefault(x => x.Id == 2);
Console.WriteLine($"-----------After Update --------------------");
Console.WriteLine($"{user2.Id}:{user2.Name}:{user2.RoleId}");
}
Console.WriteLine($"------------结束--------------------");
Console.ReadLine();
}
- 生成的SQL如下
UPDATE [x] SET x.[Name] =x.[Name] + @param_0 ,x.[RoleId] =x.[RoleId] + @param_1
FROM [User] AS [x]
WHERE [x].[Id] = 2
EFCore扩展Update方法(实现 Update User SET Id=Id+1)的更多相关文章
- EFCore扩展Select方法(根据实体定制查询语句)
EFCore扩展Select方法(根据实体定制查询语句) 通常用操作数据库的时候查询返回的字段是跟 我们的定义的实体是不一致的,所以往往针对UI或者接口层创建大量的Model, 而且需要手动对应字段 ...
- MongoDB学习笔记~Update方法更新集合属性后的怪问题
回到目录 在对MongoDB进行封装后,对于Update更新对象里的集合属性时出现了一个现象,让人感到很恶心,人家更新前是个美丽的Array,但是更新之后集合对象变成了键值对,键是集合的类型名称,值是 ...
- hibernate persist update 方法没有正常工作(不保存数据,不更新数据)
工程结构 问题描述 在工程中通过spring aop的方式配置事务,使用hibernate做持久化.在代码实现中使用hibernate persit()方法插入数据到数据库,使用hibernate u ...
- MongoDB中insert方法、update方法、save方法简单对比
MongoDB中insert方法.update方法.save方法简单对比 1.update方法 该方法用于更新数据,是对文档中的数据进行更新,改变则更新,没改变则不变. 2.insert方法 该方法用 ...
- hibernate中保存一个对象后再设置此对象的属性为什么不需要调用update方法了
hibernate中保存一个对象后再设置此对象的属性为什么不需要调用update方法了 例如session.save(user);user.setAge(20); 原因: hibernate对象的三种 ...
- Unity3d中Update()方法的替身
在网上看到一些资料说Unity3d的Update方法是如何如何不好,影响性能.作为一个菜鸟,之前我还觉得挺好用的,完全没用什么影响性能的问题存在.现在发现确实有很大的问题,我习惯把一大堆检测判断放在U ...
- [原创]java WEB学习笔记79:Hibernate学习之路--- 四种对象的状态,session核心方法:save()方法,persist()方法,get() 和 load() 方法,update()方法,saveOrUpdate() 方法,merge() 方法,delete() 方法,evict(),hibernate 调用存储过程,hibernate 与 触发器协同工作
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- Hibernate中的session对象update方法的使用
使一个游离对象转变为持久化对象.例如以下代码在session1中保存了一个Customer对象,然后在session2中更新这个Customer对象: Customer customer = new ...
- 05 - 替换vtkDataObject中的Update方法 VTK 6.0 迁移
VTK6 引入了许多不兼容的变.其中之一是删除vtkDataObject中所有有关管道的方法.下面讨论update方法并提供迁移现有代码的建议. Update() vtkDataObject::Upd ...
随机推荐
- 常用FTP命令 1. 连接ftp服务器
1. 连接ftp服务器 格式:ftp [hostname| ip-address]a)在linux命令行下输入: ftp 192.168.1.1 b)服务器询问你用户名和密码,分别输入用户名和相应密码 ...
- zufeoj 花生(The Peanuts)
花生(The Peanuts) 时间限制: 1 Sec 内存限制: 128 MB提交: 3 解决: 2[提交][状态][讨论版] 题目描述 鲁宾逊先生和他的宠物猴,多多,非常喜欢花生.有一天,他们 ...
- JAVA面试(5)
这里列出10条JAVA编程经验 1 字符串常量放在前面 把字符串常量放在equals()比较项的左侧来防止偶然的NullPointerException. // Bad if (variable.eq ...
- Altium Designer之多图纸设计
Altium Designer的多图纸功能感觉比较方便:今天翻了下徐老师<Altium Designer 快速入门>里面关于多图纸设计的介绍,再参考了altium 网站的一些资料,算是摸熟 ...
- Linux机器工作环境安装
安装gcc编译器: yum -y install gcc 安装wget: yum -y install wget 安装python-setuptools: wget http://peak.telec ...
- 04.CSS的继承性和层叠性
CSS有两大特性: 继承性和层叠性 继承性 面向对象语言都会存在继承的概念 , 在面向对象语言中, 继承的特点: 继承了父类的属性和方法. 那么 css 就是在设置属性的 , 不会牵扯到方法 ...
- python拷贝文件小程序(windows)
#!/usr/bin/python import os source='F:\\lh.jpg' target='E:\\' copy_command="xcopy %s %s"%( ...
- noip2010 关押罪犯 (vijos1776)
题目 S城现有两座监狱,一共关押着N名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用“怨气值”(一个正整数值)来表示某两名罪 ...
- 189. Rotate Array 从右边开始翻转数组
[抄题]: Rotate an array of n elements to the right by k steps. For example, with n = 7 and k = 3, the ...
- 我使用的网址--Hadoop
1.Hadoop 官网下载:http://hadoop.apache.org/releases.html 各版本网址:http://mirror.bit.edu.cn/apache/hadoop/co ...