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() > 0)
            {
                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)) == 0)
                              && !(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() == 0)
                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 != 0)
                    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 == 0)
                throw new Exception("沒有任何屬性進行更新");

            builder.Insert(0, " 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)) == "0")
                    continue;
                object value = member.GetValue(entity, null);
                if (value != null)
                {
                    if (arguments.Count != 0)
                    {
                        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 == 0)
                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() > 0);
            if (retu != null && retu.Count() > 0)
                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 > 0)
                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,
    }
View Code

 

 

參考:


免責聲明!

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



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