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直接使用网站原有的用户数据库,而不需要将已有的 ...
随机推荐
- 扩展GroupBox控件
1.GroupBox的边框颜色可以自行设置: 2.GroupBox可以设置边框的为圆角: 3.设置GroupBox标题在控件中的位置. 4.设置GroupBox标题的字体和颜色. 具体实现步骤Pane ...
- 苹果电脑基本设置+Linux 命令+Android 实战集锦
本文微信公众号「AndroidTraveler」首发. 背景 大多数应届毕业生在大学期间使用的比较多的是 windows 电脑,因此初入职场如果拿到一台苹果电脑,可能一时间不能够很快的上手.基于此,这 ...
- Docker:镜像的迁移
从202将现有镜像搬到207的过程. 先说导出,两种方法:Docker save 和 docker export,前者保存镜像,后者导出容器. docker save docker.io/java:7 ...
- 启xin宝app的token算法破解——token分析篇(三)
前两篇文章分析该APP的抓包.的逆向: 启xin宝app的token算法破解--抓包分析篇(一) 启xin宝app的token算法破解--逆向篇(二) 本篇就将对token静态分析,其实很简单就可以搞 ...
- 12款好用超赞的国外搜索资源网站 ,开发者们的标配,你都知道吗?不知道就OUT了
简介 看了 看了网上有好多推荐插件的文章,很少有推荐搜索资源网站,于是今天决定推荐一波搜索资源网站.这些网站带给我开阔视眼增长知识.所以在这里整理一下,分享给朋友和博友们. 学习技术过程我们经常需要使 ...
- d3.js V5版本在vue里使用 自定义节点图片
var width = this.$refs.topInfo.offsetWidth; var height = this.$refs.topInfo.offsetHeight; var img_w ...
- python 39 socketserver 模块并发通信
socketserver模块 socketserver模块实现一个服务端与多个客户端通信.是在socket的基础上进行了一层封装,底层还是调用的socket. socketserver干了两件事: 1 ...
- 【CocosBuilder】学习笔记目录
从2019年8月底开始学习CocosBuilder. CocosBuilder 学习笔记(1) CCBReader 解析.ccbi文件流程 CocosBuilder 学习笔记(2) .ccbi 文 ...
- 从零开始搭建Java开发环境第二篇:如何在windows10里安装MySQL
1 下载安装包 1.1 压缩包 https://dev.mysql.com/downloads/mysql/ [外链图片转存失败(img-oesO8K09-1566652568838)(data:im ...
- 如何编写高质量的 JS 函数(2) -- 命名/注释/鲁棒篇
本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/sd2oX0Z_cMY8_GvFg8pO4Q作者:杨昆 上篇<如何编写高质量的 JS 函数 ...