C#中的根据实体增删改操作
在日常操作中,我们经常会对一些数据进行批量更新,
我在使用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#中的根据实体增删改操作的更多相关文章
- C#,记录--一个方法中,完成对数据增删改操作
实际应用中,一般不会使用delete彻底的删除数据,大多都是逻辑删除 为了不把本文写成小作文,举个小栗子吧 表 A,deletestate为置删除字段,int类型,值为0和1 表中五条数据 查询 se ...
- Elasticsearch6.8.6版本 在head插件中 对数据的增删改操作
一.访问ES方法:http://IP:PORT/ 一.创建索引:head插件创建索引的实例:在"索引"-"新建索引"中创建索引名称,默认了分片与副本情况: 直接 ...
- node.js中对 mysql 进行增删改查等操作和async,await处理
要对mysql进行操作,我们需要安装一个mysql的库. 一.安装mysql库 npm install mysql --save 二.对mysql进行简单查询操作 const mysql = requ ...
- (数据科学学习手札126)Python中JSON结构数据的高效增删改操作
本文示例代码及文件已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 在上一期文章中我们一起学习了在Python ...
- java中集合的增删改操作及遍历总结
集合的增删改操作及遍历总结
- OracleHelper(对增删改查分页查询操作进行了面向对象的封装,对批量增删改操作的事务封装)
公司的一个新项目使用ASP.NET MVC开发,经理让我写个OracleHelper,我从网上找了一个比较全的OracleHelper类,缺点是查询的时候返回DataSet,数据增删改要写很多代码(当 ...
- 第一节: 结合EF的本地缓存属性来介绍【EF增删改操作】的几种形式
一. 背景 说起EF的增删改操作,相信很多人都会说,有两种方式:① 通过方法操作 和 ② 通过状态控制. 相信你在使用EF进行删除或修改操作的时候,可能会遇到以下错误:“ The object c ...
- ASP.NET MVC深入浅出(被替换) 第一节: 结合EF的本地缓存属性来介绍【EF增删改操作】的几种形式 第三节: EF调用普通SQL语句的两类封装(ExecuteSqlCommand和SqlQuery ) 第四节: EF调用存储过程的通用写法和DBFirst模式子类调用的特有写法 第六节: EF高级属性(二) 之延迟加载、立即加载、显示加载(含导航属性) 第十节: EF的三种追踪
ASP.NET MVC深入浅出(被替换) 一. 谈情怀-ASP.NET体系 从事.Net开发以来,最先接触的Web开发框架是Asp.Net WebForm,该框架高度封装,为了隐藏Http的无状态 ...
- 在SQL Server中对视图进行增删改
原文:在SQL Server中对视图进行增删改 Lesktop开源IM发布以后,有一些网友问及如何在嵌入IM后与自己网站的用户系统整合(即如何让嵌入的IM直接使用网站原有的用户数据库,而不需要将已有的 ...
随机推荐
- 【POJ - 3255】Roadblocks(次短路 Dijkstra算法)
Roadblocks 直接翻译了 Descriptions Bessie搬到了一个新的农场,有时候他会回去看他的老朋友.但是他不想很快的回去,他喜欢欣赏沿途的风景,所以他会选择次短路,因为她知道一定有 ...
- cs231n---循环神经网络
1 RNN介绍 (1)一对多,多对一,多对多的任务 传统的神经网络只能处理一对一的任务,而RNN可以处理一对多,多对一,多对多的任务: 其中,一些典型的应用如下: Image Captioning:i ...
- 使用webpack---安装webpack和webpack-dev-server
1.先确保安装了最新版的Node.js和NPM,并已经了解NPM的基本用法 (以下使用cmd命令行进行) 2.安装webpack (1)全局安装 $ npm install webpack -g ...
- 《大牛到底是如何阅读JDK源码的?》一起来学习一下
前言: 如何阅读源码,是每个程序员需要面临的一项挑战,为什么需要阅读源码?从实用性的角度来看,主要有三个目的: 第一,解决手头的新问题或者新需求; 第二,真正理解一部分理论的落地实现; 第三,应对面试 ...
- PostgreSQL创建扩展出错
问题: loraserver_as=# create extension pg_trgm; ERROR: could not open extension control file "/us ...
- Spring Boot 与 Mybatis、Mysql整合使用的例子
第一步: 创建一个SpringBoot的工程,在其中的Maven依赖配置中添加对JDBC.MyBatis.Mysql Driver的依赖具体如下: <!-- JDBC --> <de ...
- 目标检测YOLO进化史之yolov1
yolov3在目标检测领域可以算得上是state-of-art级别的了,在实时性和准确性上都有很好的保证.yolo也不是一开始就达到了这么好的效果,本身也是经历了不断地演进的. yolov1 测试图片 ...
- 一文了解:Redis主从复制
Redis主从复制 主从复制 主从复制,将一台Redis服务器的数据,复制到其他Redis服务器.前者称为主(master)节点,后者称为从(slave)节点 . 在默认的情况下,Redis都是主节点 ...
- Sqoop数据迁移工具的使用
文章作者:foochane 原文链接:https://foochane.cn/article/2019063001.html Sqoop数据迁移工具的使用 sqoop简单介绍 sqoop数据到HDF ...
- egret之移除带参数的监听事件
this.selectBtn.addEventListener(egret.TouchEvent.TOUCH_TAP, this.onClickNewIndo.bind(this,this.data) ...