EF架构~一个规范,两个实现(续)~性能可以接受的批量增删改操作

简介:

上回主要把数据操作规范及EF两种基类下的实现说了一下,今天主要针对ObjectContext情况下的批量操作作一个详细的说明,首先,要说明一点,批量操作不用ObjectContext提供的方法,而是使用拼SQL串的方式,将列表拼成一个SQL串,一次的发给数据库,这样在性能上绝对是一个质的飞越,本人尝试过,无论是EF还是linq to sql,它们提供的方法,对于列表的操作会产生N条SQL串(N=列表的长度)。

一个操作类型枚举:

1         /// <summary>
2         /// 執行SQL的類型
3         /// </summary>
4         public enum SQLType
5         {
6             Insert,
7             Update,
8             Delete,
9         }

调用方法很容易:

public void Insert<TEntity>(List<TEntity> list) where TEntity : class
        {
            DoListSQL(list, SQLType.Insert);
        }

public void Update<TEntity>(List<TEntity> list) where TEntity : class
        {
            DoListSQL<TEntity>(list, SQLType.Update);
        }

  public void Delete<TEntity>(List<TEntity> list) where TEntity : class
        {
            DoListSQL<TEntity>(list, SQLType.Delete);
        }

下面是实现这样方法的代码,即SQL串在ObjectContext环境下是如何拼接的:

  1  /// <summary>
  2         /// 构建Update语句串
  3         /// </summary>
  4         /// <typeparam name="TEntity"></typeparam>
  5         /// <param name="entity"></param>
  6         /// <returns></returns>
  7         private Tuple<string, object[]> CreateUpdateSQL<TEntity>(TEntity entity) where TEntity : class
  8         {
  9             if (entity == null)
 10                 throw new ArgumentException("The database entity can not be null.");
 11 
 12             Type entityType = entity.GetType();
 13             var table = entityType.GetProperties().Where(i => i.PropertyType != typeof(EntityKey) && i.PropertyType != typeof(EntityState)).ToArray();
 14             var primaryKeyColumns = (entity as EntityObject).GetPK();
 15             if (primaryKeyColumns == null || primaryKeyColumns.Count == 0)
 16                 throw new ArgumentException("The Table entity have not a primary key.");
 17             List<object> arguments = new List<object>();
 18             StringBuilder builder = new StringBuilder();
 19 
 20             foreach (var change in table)
 21             {
 22                 if (primaryKeyColumns.Contains(change))
 23                     continue;
 24 
 25                 if (arguments.Count != 0)
 26                     builder.Append(", ");
 27 
 28                 if (change.GetValue(entity, null) != null)
 29                 {
 30                     builder.Append(change.Name + " = {" + arguments.Count + "}");
 31 
 32                     if (change.PropertyType == typeof(string) || change.PropertyType == typeof(DateTime))
 33                         arguments.Add("'" + change.GetValue(entity, null).ToString().Replace("'", "char(39)") + "'");
 34                     else
 35                         arguments.Add(change.GetValue(entity, null));
 36                 }
 37                 else
 38                 {
 39                     builder.Append(change.Name + " = NULL, ");
 40                 }
 41             }
 42 
 43             if (builder.Length == 0)
 44                 throw new Exception("没有任何属性进行更新");
 45 
 46             builder.Insert(0, " UPDATE " + string.Format("[{0}]", entityType.Name) + " SET ");
 47 
 48             builder.Append(" WHERE ");
 49             bool firstPrimaryKey = true;
 50 
 51             foreach (var primaryField in primaryKeyColumns)
 52             {
 53                 if (firstPrimaryKey)
 54                     firstPrimaryKey = false;
 55                 else
 56                     builder.Append(" AND ");
 57 
 58                 object val = entityType.GetProperty(primaryField.Name).GetValue(entity, null);
 59                 builder.Append(GetEqualStatment(primaryField.Name, arguments.Count));
 60                 arguments.Add(val);
 61             }
 62             return new Tuple<string, object[]>(builder.ToString(), arguments.ToArray());
 63 
 64         }
 65 
 66         /// <summary>
 67         /// 构建Insert语句串
 68         /// 主键为自增时,如果主键值为0,我们将主键插入到SQL串中
 69         /// </summary>
 70         /// <typeparam name="TEntity"></typeparam>
 71         /// <param name="entity"></param>
 72         /// <returns></returns>
 73         private Tuple<string, object[]> CreateInsertSQL<TEntity>(TEntity entity) where TEntity : class
 74         {
 75             if (entity == null)
 76                 throw new ArgumentException("The database entity can not be null.");
 77 
 78             Type entityType = entity.GetType();
 79             var table = entityType.GetProperties().Where(i => i.PropertyType != typeof(EntityKey) && i.PropertyType != typeof(EntityState)).ToArray();
 80             var primaryKeyColumns = (entity as EntityObject).GetPK();
 81 
 82             List<object> arguments = new List<object>();
 83             StringBuilder fieldbuilder = new StringBuilder();
 84             StringBuilder valuebuilder = new StringBuilder();
 85 
 86             fieldbuilder.Append(" INSERT INTO " + string.Format("[{0}]", entityType.Name) + " (");
 87 
 88             foreach (var member in table)
 89             {
 90                 if (primaryKeyColumns.Contains(member) && Convert.ToString(member.GetValue(entity, null)) == "0")
 91                     continue;
 92                 object value = member.GetValue(entity, null);
 93                 if (value != null)
 94                 {
 95                     if (arguments.Count != 0)
 96                     {
 97                         fieldbuilder.Append(", ");
 98                         valuebuilder.Append(", ");
 99                     }
100 
101                     fieldbuilder.Append(member.Name);
102                     if (member.PropertyType == typeof(string) || member.PropertyType == typeof(DateTime))
103                         valuebuilder.Append("'{" + arguments.Count + "}'");
104                     else
105                         valuebuilder.Append("{" + arguments.Count + "}");
106                     if (value.GetType() == typeof(string))
107                         value = value.ToString().Replace("'", "char(39)");
108                     arguments.Add(value);
109 
110                 }
111             }
112 
113 
114             fieldbuilder.Append(") Values (");
115 
116             fieldbuilder.Append(valuebuilder.ToString());
117             fieldbuilder.Append(");");
118             return new Tuple<string, object[]>(fieldbuilder.ToString(), arguments.ToArray());
119         }
120         /// <summary>
121         /// 构建Delete语句串
122         /// </summary>
123         /// <typeparam name="TEntity"></typeparam>
124         /// <param name="entity"></param>
125         /// <returns></returns>
126         private Tuple<string, object[]> CreateDeleteSQL<TEntity>(TEntity entity) where TEntity : class
127         {
128             if (entity == null)
129                 throw new ArgumentException("The database entity can not be null.");
130 
131             Type entityType = entity.GetType();
132             var table = entityType.GetProperties().Where(i => i.PropertyType != typeof(EntityKey) && i.PropertyType != typeof(EntityState)).ToArray();
133             var primaryKeyColumns = (entity as EntityObject).GetPK();
134             if (primaryKeyColumns == null || primaryKeyColumns.Count == 0)
135                 throw new ArgumentException("The Table entity have not a primary key.");
136 
137             List<object> arguments = new List<object>();
138             StringBuilder builder = new StringBuilder();
139             builder.Append(" Delete from " + string.Format("[{0}]", entityType.Name));
140 
141             builder.Append(" WHERE ");
142             bool firstPrimaryKey = true;
143 
144             foreach (var primaryField in primaryKeyColumns)
145             {
146                 if (firstPrimaryKey)
147                     firstPrimaryKey = false;
148                 else
149                     builder.Append(" AND ");
150 
151                 object val = entityType.GetProperty(primaryField.Name).GetValue(entity, null);
152                 builder.Append(GetEqualStatment(primaryField.Name, arguments.Count));
153                 arguments.Add(val);
154             }
155             return new Tuple<string, object[]>(builder.ToString(), arguments.ToArray());
156         }
157 
158 
159         /// <summary>
160         /// 执行实体列表以SQL串的方式
161         /// </summary>
162         /// <typeparam name="TEntity"></typeparam>
163         /// <param name="list"></param>
164         private void DoListSQL<TEntity>(IEnumerable<TEntity> list, SQLType sqlType) where TEntity : class
165         {
166             StringBuilder sqlstr = new StringBuilder();
167 
168             switch (sqlType)
169             {
170                 case SQLType.Insert:
171                     list.ToList().ForEach(i =>
172                    {
173                        Tuple<string, object[]> sql = CreateInsertSQL(i);
174                        sqlstr.AppendFormat(sql.Item1, sql.Item2);
175                    });
176                     break;
177                 case SQLType.Update:
178                     list.ToList().ForEach(i =>
179                     {
180                         Tuple<string, object[]> sql = CreateUpdateSQL(i);
181                         sqlstr.AppendFormat(sql.Item1, sql.Item2);
182                     });
183                     break;
184                 case SQLType.Delete:
185                     list.ToList().ForEach(i =>
186                    {
187                        Tuple<string, object[]> sql = CreateDeleteSQL(i);
188                        sqlstr.AppendFormat(sql.Item1, sql.Item2);
189                    });
190                     break;
191                 default:
192                     throw new ArgumentException("请输入正确的参数");
193             }
194 
195             _db.ExecuteStoreCommand(sqlstr.ToString());
196         }

代码在vs2010+sql2005+mvc3环境下测试通过

本文转自博客园张占岭(仓储大叔)的博客,原文链接:EF架构~一个规范,两个实现(续)~性能可以接受的批量增删改操作,如需转载请自行联系原博主。

目录
相关文章
|
7月前
|
存储 调度 C++
16 倍性能提升,成本降低 98%! 解读 SLS 向量索引架构升级改造
大规模数据如何进行语义检索? 当前 SLS 已经支持一站式的语义检索功能,能够用于 RAG、Memory、语义聚类、多模态数据等各种场景的应用。本文分享了 SLS 在语义检索功能上,对模型推理和部署、构建流水线等流程的优化,最终带给用户更高性能和更低成本的针对大规模数据的语义索引功能。
620 64
|
9月前
|
存储 数据挖掘 BI
2-5 倍性能提升,30% 成本降低,阿里云 SelectDB 存算分离架构助力波司登集团实现降本增效
波司登集团升级大数据架构,采用阿里云数据库 SelectDB 版,实现资源隔离与弹性扩缩容,查询性能提升 2-5 倍,总体成本降低 30% 以上,效率提升 30%,助力销售旺季高效运营。
582 9
|
负载均衡 算法 关系型数据库
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
本文聚焦 MySQL 集群架构中的负载均衡算法,阐述其重要性。详细介绍轮询、加权轮询、最少连接、加权最少连接、随机、源地址哈希等常用算法,分析各自优缺点及适用场景。并提供 Java 语言代码实现示例,助力直观理解。文章结构清晰,语言通俗易懂,对理解和应用负载均衡算法具有实用价值和参考价值。
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
|
11月前
|
人工智能 API 数据安全/隐私保护
Apifox 与 Apipost 的 API 文档引擎对比:底层架构、性能与可扩展性分析
深入探索市场上两大主流API工具——Apifox和Apipost的文档能力时,发现了令人惊讶的差距。这不仅仅是功能多寡的问题,更关乎开发效率与团队协作的质变。
|
SQL 缓存 分布式计算
vivo 湖仓架构的性能提升之旅
聚焦 vivo 大数据多维分析面临的挑战、StarRocks 落地方案及应用收益。 在 **即席分析** 场景,StarRocks 使用占比达 70%,查询速度提升 3 倍,P50 耗时从 63.77 秒缩短至 22.30 秒,查询成功率接近 98%。 在 **敏捷 BI** 领域,StarRocks 已完成 25% 切换,月均查询成功数超 25 万,P90 查询时长缩短至 5 秒,相比 Presto 提升 75%。 在 **研发工具平台** 方面,StarRocks 支持准实时数据查询,数据可见性缩短至 3 分钟,查询加速使 P95 延迟降至 400 毫秒,开发效率提升 30%。
vivo 湖仓架构的性能提升之旅
|
8月前
|
存储 JSON 数据处理
ClkLog埋点与用户行为分析系统:架构升级与性能全面提升
随着越来越多企业在实际业务中使用 ClkLog,数据规模和分析需求也不断提升,部分用户日活已经超过10万,为了顺应这一趋势,ClkLog 秉持 “开放透明、持续演进”的理念,推出了迄今为止最重要的一次性能优化升级。新版本在大规模数据处理与复杂查询场景中,性能表现实现了跨越式提升。经过多轮研发与严格测试,新版本现已正式上线:在原有付费版 1.0 的基础上架构全面升级,并同步发布全新的 2.0 版本。为用户带来更强的性能与更广的适用场景。
|
11月前
|
关系型数据库 MySQL 分布式数据库
Super MySQL|揭秘PolarDB全异步执行架构,高并发场景性能利器
阿里云瑶池旗下的云原生数据库PolarDB MySQL版设计了基于协程的全异步执行架构,实现鉴权、事务提交、锁等待等核心逻辑的异步化执行,这是业界首个真正意义上实现全异步执行架构的MySQL数据库产品,显著提升了PolarDB MySQL的高并发处理能力,其中通用写入性能提升超过70%,长尾延迟降低60%以上。
|
11月前
|
存储 缓存 分布式计算
高内存场景必读!阿里云r7/r9i/r8y/r8i实例架构、性能、价格多维度对比
阿里云针对高性能需求场景,一般会在活动中推出内存型r7、内存型r9i、内存型r8y和内存型r8i这几款内存型实例规格的云服务器。相比于活动内的经济型e和通用算力型u1等实例规格,这些内存型实例在性能上更为强劲,尤其适合对内存和计算能力有较高要求的应用场景。这些实例规格的云服务器在处理器与内存的配比上大多为1:8,但它们在处理器架构、存储性能、网络能力以及安全特性等方面各有千秋,因此适用场景也各不相同。本文将为大家详细介绍内存型r7、r9i、r8y、r8i实例的性能、适用场景的区别以及选择参考。