即使用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更快:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM