zoukankan      html  css  js  c++  java
  • 即使用ADO.NET,也要轻量级动态生成更新SQL,比Ormlite性能更高

    先上测试结果:

            //测试1000次针对同一个表同一个字段更新,比Ormlite平均快2.34倍
            //生成SQL+ExecuteNonQuery   Ormlite     倍数
            //6513ms                    15158ms        2.327
            //6461ms                    15303ms        2.369
            //6624ms                    15424ms        2.329
            //6591ms                    15468ms        2.347
    
            //测试1000次针对同一个表同一个字段更新,比EF平均快1.68倍
            //生成SQL+ExecuteNonQuery   EF          倍数
            //6622ms                    11113ms        1.678    
            //6577ms                    11117ms        1.690
            //6756ms                    11258ms        1.666    
            //6603ms                    11184ms        1.694


    不管出于什么原因,有时候框架人员摒弃了NH或EF,而使用原生数据库访问对象。

    为了优美的编程,用上我写的轻量级动态生成更新SQL扩展方法吧

    还记得在EF中只更新修改过的字段时,我们这么写:

                            var e = db.Entry(d);
                            e.State = EntityState.Unchanged;
                            d.UploadTime = DateTime.Now;
                            e.Property("UploadTime").IsModified = true;
                            db.SaveChanges();

    目的是,使生成的更新SQL只更新UploadTime字段,否则会更新所有字段,那么就需要先查询一遍再更新。
    既然提到数据仓储,我们更新一个实体在数据层最好只有一个方法,但是一个更新的SQL能满足要求吗?

    出于以上目的,我写了这样的轻量级扩展方法:

        /// <summary>
        /// 
        /// </summary>
        public static class SqlStringEx
        {
            #region 静态私有成员
    
            private static object _obj = new object();
    
            private static Dictionary<int, PropertyInfo[]> propertiesCache = new Dictionary<int, PropertyInfo[]>();
    
            /// <summary>
            /// 从缓存中获取属性信息
            /// </summary>
            /// <param name="t"></param>
            /// <returns></returns>
            private static PropertyInfo[] GetPropertiesFromCache(Type t)
            {
                var code = t.GetHashCode();
                if (!propertiesCache.ContainsKey(code))
                {
                    lock (_obj)
                    {
                        if (!propertiesCache.ContainsKey(code))
                        {
                            propertiesCache.Add(code, t.GetProperties());
                        }
                    }
                }
                return propertiesCache[code];
            }
            #endregion
    
    
            /// <summary>
            /// 根据实体模型的赋值情况,动态生成更新SQL。避免要先获取再保存,或者避免按需写多个更新SQL
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="t"></param>
            /// <param name="tableName">数据表名称</param>
            /// <param name="conditionColumnName">更新时条件列名称,该列名需包含在parameters中</param>
            /// <param name="parameters"></param>
            /// <returns></returns>
            public static string GenerateUpdateSql<T>(this T t, string tableName, string conditionColumnName, out List<SqlParameter> parameters)
                where T : new()
            {
    
                parameters = new List<SqlParameter>();
                StringBuilder res = new StringBuilder();
                res.AppendFormat("update {0} set ", tableName);
                var props = GetPropertiesFromCache(t.GetType());
                string wherePart = null;
                foreach (PropertyInfo item in props)
                {
                    var propVal = item.GetValue(t, null);
                    var hasValue = propVal != null && !propVal.Equals(0);
                    if (hasValue)
                    {
                        var filedname = item.GetFieldName();
                        parameters.Add(new SqlParameter { Value = propVal, ParameterName = filedname });
                        if (filedname.Equals(conditionColumnName.ToLower()))
                        {
                            wherePart = string.Format(" where {0}=@{0} ", filedname);
                        }
                        else
                        {
                            res.AppendFormat(" {0}=@{0} ,", filedname);
                        }
                    }
                }
                res.Remove(res.Length - 1, 1);
                res.Append(wherePart);
                return res.ToString();
            }
        }

    其中的GetFieldName()方法见上一篇

    有了这个方法,数据层一个实体就只需要一个更新的方法,也不需要自己去拼接更新的SQL了。

                List<SqlParameter> parameters =null;
                var saveSql = model.GenerateUpdateSql("TableName", "ID", out parameters);

    注意,model的属性的默认值分两种,值类型默认值为0,引用类型和非空值类型的默认值是null,当model属性的值不是默认值的时候会参与值的更新
    saveSql就是我们要更新的SQL,parameters是对应更新的参数。ID参数也可以是别的列,但在model中作为条件的列的值不能为默认值。

    有没有很方便,欢迎抛砖。

    虽然重复造轮子,但方便性是不是可以弥补一切。

    性能要求高的,请慎重考虑,因为内部使用了反射。但是性能总的来说比Ormlite更快,执行1000次更新,本扩展方法耗时6513毫秒,而Ormlite耗时15158毫秒。

    EF相比Ormlite更快:

  • 相关阅读:
    Server has no associated SOC machines or all SOC machines are at capacity
    没有启用集成windows身份验证
    Arcgis server常见问题
    把.NET程序部署到没有安装.NET Framwork的机器上
    将图片保存到数据库表中及从数据库表中读取图片并显示
    C#实现QQ靠边隐藏的功能
    手把手教你用C#打包应用程序(安装程序)【卸载模块已添加】
    DotNet下简单的程序部署
    部署.NET平台的程序实例浅析
    程序打包
  • 原文地址:https://www.cnblogs.com/langu/p/4576631.html
Copyright © 2011-2022 走看看