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

我在使用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. go 学习笔记之数组还是切片都没什么不一样

    上篇文章中详细介绍了 Go 的基础语言,指出了 Go 和其他主流的编程语言的差异性,比较侧重于语法细节,相信只要稍加记忆就能轻松从已有的编程语言切换到 Go 语言的编程习惯中,尽管这种切换可能并不是特 ...

  2. sql中#与$取值

    在mapper.xml中#与$都是用来取值的 <update id="addUrl"> update user_power set url = #{newurl} wh ...

  3. RocketMQ 4.3.2 standalone Installation and Configuration

    1 Download RockeMQ Package: You need to download it and put it to the OS Image. wget http://apache.c ...

  4. Leetcode之回溯法专题-17. 电话号码的字母组合(Letter Combinations of a Phone Number)

    [Leetcode]17. 电话号码的字母组合(Letter Combinations of a Phone Number) 题目描述: 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组 ...

  5. Salesforce LWC学习(五) LDS & Wire Service 实现和后台数据交互 & meta xml配置

    之前的几节都是基于前台变量进行相关的操作和学习,我们在项目中不可避免的需要获取数据以及进行DML操作.之前的内容中也有提到wire注解,今天就详细的介绍一下对数据进行查询以及DML操作以及Wire S ...

  6. C#开发BIMFACE系列10 服务端API之获取文件下载链接

    系列目录     [已更新最新开发文章,点击查看详细] 通过BIMFACE控制台或者调用服务接口上传文件成功后,默认场景下需要下载该源文件,下载文件一般需要知道文件的下载链接即可.BIMACE平台提供 ...

  7. Oracle中的一些基本sql语句

    --新建表create table table1 (id varchar(300) primary key,name varchar(200) not null);--插入数据insert into ...

  8. Mac应用程序无法打开或文件损坏的处理方法你知道吗?

    很多用户在安装Mac软件的时候,经常会遇到提示“xxx.app已损坏,打不开.您应该将它移到废纸篓“或”打不开的xxx.app,因为它来自身份不明的开发者”,如下图的样子: 真的损坏了么?是不是真的要 ...

  9. 大型互联网公司分布式ID方案总结

    ID是数据的唯一标识,传统的做法是利用UUID和数据库的自增ID,在互联网企业中,大部分公司使用的都是Mysql,并且因为需要事务支持,所以通常会使用Innodb存储引擎,UUID太长以及无序,所以并 ...

  10. java设计模式5.组合模式、门面模式、享元模式、桥接模式

    组合模式 在面向对象的语言中,树结构有着巨大的威力,一个基于继承的类型的等级结构便是一个数结构,一个基于合成的对象结构也是一个数结构.组合模式将部分与整体的关系用树结构表示出来,使得客户端把一个个单独 ...