在日常操作中,我们经常会对一些数据进行批量更新,

我在使用EF的时候,没有找到比较好的批量更新的解决方案,

便参考了张占岭前辈的博客,整合了这么一个简略版的使用实体类生成数据库增删改SQL的操作类

在进行更新和删除的时候,会针对的主键进行更新或者删除,所以我们需要给实体类用于主键的字段进行一个特性的标识

下面贴上代码,有不足或者错误之处希望大家多多指正

  /// <summary>
/// 根据实体来生成批量新增、修改、删除的Sql语句
/// 在Update和Delete
/// </summary>
/// <typeparam name="TEntity">实体</typeparam>
public class EntityToSQL<TEntity> where TEntity : class
{ #region 根据集合获取SQL语句 /// <summary>
/// 执行SQL,根据SQL操作的类型
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="list"></param>
/// <param name="sqlType"></param>
/// <returns></returns>
/// </summary>
/// <param name="list"></param>
/// <param name="sqlType"></param>
/// <returns></returns>
public static string GetSql(IEnumerable<TEntity> list, SqlType sqlType)
{
return GetSql(list, sqlType, null);
} /// <summary>
/// 执行SQL,根据SQL操作的类型
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="list"></param>
/// <param name="sqlType"></param>
/// <returns></returns>
public static string GetSql(IEnumerable<TEntity> list, SqlType sqlType, params string[] fieldParams)
{
var sqlstr = new StringBuilder();
switch (sqlType)
{
case SqlType.Insert:
list.ToList().ForEach(i =>
{
Tuple<string, object[]> sql = CreateInsertSql(i);
sqlstr.AppendFormat(sql.Item1, sql.Item2);
});
break;
case SqlType.Update:
list.ToList().ForEach(i =>
{
Tuple<string, object[]> sql = CreateUpdateSql(i, fieldParams);
sqlstr.AppendFormat(sql.Item1, sql.Item2);
});
break;
case SqlType.Delete:
list.ToList().ForEach(i =>
{
Tuple<string, object[]> sql = CreateDeleteSql(i);
sqlstr.AppendFormat(sql.Item1, sql.Item2);
});
break;
default:
throw new ArgumentException("请输入正确的参数");
}
return sqlstr.ToString();
} #endregion #region 构建Update语句串 /// <summary>
/// 构建Update语句串
/// 注意:如果本方法过滤了int,decimal类型更新为0的列,如果希望更新它们需要指定FieldParams参数
/// </summary>
/// <param name="entity">实体列表</param>
/// <param name="fieldParams">要更新的字段</param>
/// <returns></returns>
private static Tuple<string, object[]> CreateUpdateSql(TEntity entity, params string[] fieldParams)
{
if (entity == null)
throw new ArgumentException("数据库实体不能为空");
List<string> pkList = GetPrimaryKeyName(); var entityType = entity.GetType();
var tableFields = new List<PropertyInfo>();
if (fieldParams != null && fieldParams.Count() > )
{
tableFields = entityType.GetProperties().Where(i => fieldParams.Contains(i.Name, StringComparer.OrdinalIgnoreCase)).ToList();
}
else
{
tableFields = entityType.GetProperties().Where(i =>
!pkList.Contains(i.Name)
&& i.GetValue(entity, null) != null
&& !i.PropertyType.IsEnum
&& !(i.PropertyType == typeof(ValueType) && Convert.ToInt64(i.GetValue(entity, null)) == )
&& !(i.PropertyType == typeof(DateTime) && Convert.ToDateTime(i.GetValue(entity, null)) == DateTime.MinValue)
&& i.PropertyType != typeof(EntityState)
&& i.GetCustomAttributes(false).Where(j => j.GetType() == typeof(NavigationAttribute)) != null//过滤导航属性
&& (i.PropertyType.IsValueType || i.PropertyType == typeof(string))
).ToList();
}
//过滤主键,航行属性,状态属性等
if (pkList == null || pkList.Count() == )
throw new ArgumentException("表实体没有主键");
var arguments = new List<object>();
var builder = new StringBuilder(); foreach (var change in tableFields)
{
if (pkList.Contains(change.Name))
continue;
if (arguments.Count != )
builder.Append(", ");
builder.Append(change.Name + " = {" + arguments.Count + "}");
if (change.PropertyType == typeof(string)
|| change.PropertyType == typeof(DateTime)
|| change.PropertyType == typeof(DateTime?)
|| change.PropertyType == typeof(bool?)
|| change.PropertyType == typeof(bool))
arguments.Add("'" + change.GetValue(entity, null).ToString().Replace("'", "char(39)") + "'");
else
arguments.Add(change.GetValue(entity, null));
} if (builder.Length == )
throw new Exception("没有任何属性进行更新"); builder.Insert(, " UPDATE " + string.Format("[{0}]", entityType.Name) + " SET "); builder.Append(" WHERE ");
bool firstPrimaryKey = true; foreach (var primaryField in pkList)
{
if (firstPrimaryKey)
firstPrimaryKey = false;
else
builder.Append(" AND "); object val = entityType.GetProperty(primaryField).GetValue(entity, null);
Type pkType = entityType.GetProperty(primaryField).GetType();
builder.Append(GetEqualStatment(primaryField, arguments.Count, pkType));
arguments.Add(val);
}
return new Tuple<string, object[]>(builder.ToString(), arguments.ToArray()); } #endregion #region 构建Insert语句串 /// <summary>
/// 构建Insert语句串
/// 主键为自增时,如果主键值为0,我们将主键插入到SQL串中
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="entity"></param>
/// <returns></returns>
private static Tuple<string, object[]> CreateInsertSql(TEntity entity)
{
if (entity == null)
throw new ArgumentException("数据库实体不能为空"); Type entityType = entity.GetType();
var table = entityType.GetProperties().Where(i => i.PropertyType != typeof(EntityKey)
&& i.PropertyType != typeof(EntityState)
&& i.Name != "IsValid"
&& i.GetValue(entity, null) != null
&& !i.PropertyType.IsEnum
&& i.GetCustomAttributes(false).Where(j => j.GetType() == typeof(NavigationAttribute)) != null
&& (i.PropertyType.IsValueType || i.PropertyType == typeof(string))).ToArray();//过滤主键,航行属性,状态属性等 var pkList = new List<string>();
if (GetPrimaryKey() != null)//有时主键可能没有设计,这对于添加操作是可以的
pkList = GetPrimaryKeyName();
var arguments = new List<object>();
var fieldbuilder = new StringBuilder();
var valuebuilder = new StringBuilder(); fieldbuilder.Append(" INSERT INTO " + string.Format("[{0}]", entityType.Name) + " ("); foreach (var member in table)
{
if (pkList.Contains(member.Name) && Convert.ToString(member.GetValue(entity, null)) == "")
continue;
object value = member.GetValue(entity, null);
if (value != null)
{
if (arguments.Count != )
{
fieldbuilder.Append(", ");
valuebuilder.Append(", ");
} fieldbuilder.Append(member.Name);
if (member.PropertyType == typeof(string)
|| member.PropertyType == typeof(DateTime)
|| member.PropertyType == typeof(DateTime?)
|| member.PropertyType == typeof(Boolean?)
|| member.PropertyType == typeof(Boolean)
)
valuebuilder.Append("'{" + arguments.Count + "}'");
else
valuebuilder.Append("{" + arguments.Count + "}");
if (value is string)
value = value.ToString().Replace("'", "char(39)");
arguments.Add(value); }
} fieldbuilder.Append(") Values (");
fieldbuilder.Append(valuebuilder.ToString());
fieldbuilder.Append(");");
return new Tuple<string, object[]>(fieldbuilder.ToString(), arguments.ToArray());
} #endregion #region 构建Delete语句串 /// <summary>
/// 构建Delete语句串
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="entity"></param>
/// <returns></returns>
private static Tuple<string, object[]> CreateDeleteSql(TEntity entity)
{
if (entity == null)
throw new ArgumentException("数据库实体不能为空"); Type entityType = entity.GetType();
List<string> pkList = GetPrimaryKeyName();
if (pkList == null || pkList.Count == )
throw new ArgumentException("表实体没有主键"); var arguments = new List<object>();
var builder = new StringBuilder();
builder.Append(" Delete from " + string.Format("[{0}]", entityType.Name)); builder.Append(" WHERE ");
bool firstPrimaryKey = true; foreach (var primaryField in pkList)
{
if (firstPrimaryKey)
firstPrimaryKey = false;
else
builder.Append(" AND "); Type pkType = entityType.GetProperty(primaryField).GetType();
object val = entityType.GetProperty(primaryField).GetValue(entity, null);
builder.Append(GetEqualStatment(primaryField, arguments.Count, pkType));
arguments.Add(val);
}
return new Tuple<string, object[]>(builder.ToString(), arguments.ToArray());
} #endregion #region 准备参数 /// <summary>
/// 获取Where条件
/// </summary>
/// <param name="fieldName"></param>
/// <param name="paramId"></param>
/// <param name="pkType"></param>
/// <returns></returns>
private static string GetEqualStatment(string fieldName, int paramId, Type pkType)
{
if (pkType.IsValueType)
return string.Format("{0} = {1}", fieldName, GetParamTag(paramId));
return string.Format("{0} = '{1}'", fieldName, GetParamTag(paramId));
} private static string GetParamTag(int paramId)
{
return "{" + paramId + "}";
} /// <summary>
/// 获取标识为主键或者导航属性的属性
/// </summary>
/// <returns></returns>
private static List<PropertyInfo> GetPrimaryKey()
{
Type entityType = typeof(TEntity);
var retu = entityType.GetProperties().Where(x =>
x.GetCustomAttributes().Where(j => j.GetType() == typeof(NavigationAttribute)).Count() > );
if (retu != null && retu.Count() > )
return retu.ToList();
return null;
} /// <summary>
/// 获取特性的名字
/// </summary>
/// <returns></returns>
private static List<string> GetPrimaryKeyName()
{
List<string> resu = new List<string>();
List<PropertyInfo> list = GetPrimaryKey();
if (list != null && list.Count > )
resu = list.Select(x => x.Name).ToList();
return resu;
} #endregion } /// <summary>
/// 属性的导航属性(用于标识实体的主键)
/// </summary>
public class NavigationAttribute : Attribute
{ } /// <summary>
/// SQL操作类型
/// </summary>
public enum SqlType
{
Insert,
Update,
Delete,
}
参考:

C#中的根据实体增删改操作的更多相关文章

  1. C#,记录--一个方法中,完成对数据增删改操作

    实际应用中,一般不会使用delete彻底的删除数据,大多都是逻辑删除 为了不把本文写成小作文,举个小栗子吧 表 A,deletestate为置删除字段,int类型,值为0和1 表中五条数据 查询 se ...

  2. Elasticsearch6.8.6版本 在head插件中 对数据的增删改操作

    一.访问ES方法:http://IP:PORT/ 一.创建索引:head插件创建索引的实例:在"索引"-"新建索引"中创建索引名称,默认了分片与副本情况: 直接 ...

  3. node.js中对 mysql 进行增删改查等操作和async,await处理

    要对mysql进行操作,我们需要安装一个mysql的库. 一.安装mysql库 npm install mysql --save 二.对mysql进行简单查询操作 const mysql = requ ...

  4. (数据科学学习手札126)Python中JSON结构数据的高效增删改操作

    本文示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 在上一期文章中我们一起学习了在Python ...

  5. java中集合的增删改操作及遍历总结

      集合的增删改操作及遍历总结

  6. OracleHelper(对增删改查分页查询操作进行了面向对象的封装,对批量增删改操作的事务封装)

    公司的一个新项目使用ASP.NET MVC开发,经理让我写个OracleHelper,我从网上找了一个比较全的OracleHelper类,缺点是查询的时候返回DataSet,数据增删改要写很多代码(当 ...

  7. 第一节: 结合EF的本地缓存属性来介绍【EF增删改操作】的几种形式

    一. 背景 说起EF的增删改操作,相信很多人都会说,有两种方式:① 通过方法操作  和  ② 通过状态控制. 相信你在使用EF进行删除或修改操作的时候,可能会遇到以下错误:“ The object c ...

  8. ASP.NET MVC深入浅出(被替换) 第一节: 结合EF的本地缓存属性来介绍【EF增删改操作】的几种形式 第三节: EF调用普通SQL语句的两类封装(ExecuteSqlCommand和SqlQuery ) 第四节: EF调用存储过程的通用写法和DBFirst模式子类调用的特有写法 第六节: EF高级属性(二) 之延迟加载、立即加载、显示加载(含导航属性) 第十节: EF的三种追踪

    ASP.NET MVC深入浅出(被替换)   一. 谈情怀-ASP.NET体系 从事.Net开发以来,最先接触的Web开发框架是Asp.Net WebForm,该框架高度封装,为了隐藏Http的无状态 ...

  9. 在SQL Server中对视图进行增删改

    原文:在SQL Server中对视图进行增删改 Lesktop开源IM发布以后,有一些网友问及如何在嵌入IM后与自己网站的用户系统整合(即如何让嵌入的IM直接使用网站原有的用户数据库,而不需要将已有的 ...

随机推荐

  1. 重学计算机组成原理(十)- "烫烫烫"乱码的由来

    程序 = 算法 + 数据结构 对应到计算机的组成原理(硬件层面) 算法 --- 各种计算机指令 数据结构 --- 二进制数据 计算机用0/1组成的二进制,来表示所有信息 程序指令用到的机器码,是使用二 ...

  2. Kafka 系列(四)—— Kafka 消费者详解

    一.消费者和消费者群组 在 Kafka 中,消费者通常是消费者群组的一部分,多个消费者群组共同读取同一个主题时,彼此之间互不影响.Kafka 之所以要引入消费者群组这个概念是因为 Kafka 消费者经 ...

  3. There’s More Than One Way To Do It!

    There’s More Than One Way To Do It!

  4. JavaScript在web自动化测试中的作用

    前言 JS的全称JavaScript,是一种运行在浏览器中的解释型脚本语言,通常用来实现web前端页面的基本功能,对于前端开发人员是不得不掌握的一门基本技能,但是对于做web自动化测试的人员来说,如果 ...

  5. Spring源码剖析6:Spring AOP概述

    原文出处: 五月的仓颉 我们为什么要使用 AOP 前言 一年半前写了一篇文章Spring3:AOP,是当时学习如何使用Spring AOP的时候写的,比较基础.这篇文章最后的推荐以及回复认为我写的对大 ...

  6. activemq的下载与安装

    一.介绍 Apache ActiveMQ™是最流行的开源,多协议,基于Java的消息服务器.它支持行业标准协议,因此用户可以通过广泛的语言和平台获得客户选择的好处.可以使用C,C ++,Python, ...

  7. 企查查app (二)

    企查查app sign算法破解 已删除!!!! 这次我们又找到设备id,现在就只差aXM这个了. 关注小白公众号,小白带你成长.

  8. PythonI/O进阶学习笔记_3.2面向对象编程_python的继承(多继承/super/MRO/抽象基类/mixin模式)

    前言: 本篇相关内容分为3篇多态.继承.封装,这篇为第二篇 继承. 本篇内容围绕 python基础教程这段: 在面向对象编程中,术语对象大致意味着一系列数据(属性)以及一套访问和操作这些数据的方法.使 ...

  9. 8、kubernetes之存储卷资源

    一.存储卷的类型 emptyDir:在宿主机上分一块内存空间给pod当做存储空间 hostPath:在宿主机上分一块磁盘空间给pod当做存储空间 网络存储: SAN:iSCSI,FC NAS:nfs, ...

  10. codeblocks无法调试的相关解决思路

    代码无法调试!? 难受... 现在给你提供两种常见的导致codeblocks无法调试的原因以及相应的解决方案. 原因一: 在创建工程目录时,保存路径中有中文. 重要的事情说三遍: 切记,工程目录的保存 ...