zoukankan      html  css  js  c++  java
  • EF架构~性能高效的批量操作(Update篇)

    回到目录

    很多时间之长,我写了EF架构~性能高效的批量操作(Insert篇),而今天我把Update篇也写一下,这对于批量处理数据很有帮助,它解决了EF与linq to sql批量更新数据上的效率问题。

    对于EF架构中的批量更新操作,需要我们为实体的导航属性进行手动的标示,因为EF生成的实体中没有一个特殊的说明,所以,我们必须要告诉系统,哪个属性是导航属性,而导航属性是我们不去进行update的。

    1    /// <summary>
    2     /// 属性的导航属性
    3     /// </summary>
    4     public class NavigationAttribute : Attribute
    5     {
    6 
    7     }

    而对于要进行批量更新的实体,我们需要为导航属性添加这个特性

    1    public class User
    2     {
    3         public int UserID { get; set; }
    4         [Navigation]
    5         public User_Extension User_Extension { get; set; }
    6     }

    而对于我们构建批量Update语句,请看代码,它需要对导航属性进行过滤

     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             List<string> pkList = GetPrimaryKey<TEntity>().Select(i => i.Name).ToList();
    12 
    13             Type entityType = entity.GetType();
    14             var table = entityType.GetProperties().Where(i =>
    15                 !pkList.Contains(i.Name)
    16                 && i.GetValue(entity, null) != null
    17                 && i.PropertyType != typeof(EntityState)
    18                 && !(i.GetCustomAttributes(false).Length > 0
    19                 && i.GetCustomAttributes(false).Where(j => j.GetType() == typeof(NavigationAttribute)) != null)
    20                 && (i.PropertyType.IsValueType || i.PropertyType == typeof(string)) //过滤导航属性
    21                  ).ToArray();
    22 
    23             //过滤主键,航行属性,状态属性等
    24             if (pkList == null || pkList.Count == 0)
    25                 throw new ArgumentException("The Table entity have not a primary key.");
    26             List<object> arguments = new List<object>();
    27             StringBuilder builder = new StringBuilder();
    28 
    29             foreach (var change in table)
    30             {
    31                 if (pkList.Contains(change.Name))
    32                     continue;
    33                 if (arguments.Count != 0)
    34                     builder.Append(", ");
    35                 builder.Append(change.Name + " = {" + arguments.Count + "}");
    36                 if (change.PropertyType == typeof(string) || change.PropertyType == typeof(DateTime))
    37                     arguments.Add("'" + change.GetValue(entity, null).ToString().Replace("'", "char(39)") + "'");
    38                 else
    39                     arguments.Add(change.GetValue(entity, null));
    40             }
    41 
    42             if (builder.Length == 0)
    43                 throw new Exception("没有任何属性进行更新");
    44 
    45             builder.Insert(0, " UPDATE " + string.Format("[{0}]", entityType.Name) + " SET ");
    46 
    47             builder.Append(" WHERE ");
    48             bool firstPrimaryKey = true;
    49 
    50             foreach (var primaryField in pkList)
    51             {
    52                 if (firstPrimaryKey)
    53                     firstPrimaryKey = false;
    54                 else
    55                     builder.Append(" AND ");
    56 
    57                 object val = entityType.GetProperty(primaryField).GetValue(entity, null);
    58                 builder.Append(GetEqualStatment(primaryField, arguments.Count));
    59                 arguments.Add(val);
    60             }
    61             return new Tuple<string, object[]>(builder.ToString(), arguments.ToArray());
    62 
    63         }

    而对子类公开的Update方法,我们进行了一个封装,它通过操作枚举来确实你是要insert,update还是delete,看代码

     1         /// <summary>
     2         /// 执行SQL,根据SQL操作的类型
     3         /// </summary>
     4         /// <typeparam name="TEntity"></typeparam>
     5         /// <param name="list"></param>
     6         /// <param name="sqlType"></param>
     7         /// <returns></returns>
     8         protected string DoSQL<TEntity>(IEnumerable<TEntity> list, SQLType sqlType) where TEntity : class
     9         {
    10             StringBuilder sqlstr = new StringBuilder();
    11             switch (sqlType)
    12             {
    13                 case SQLType.Insert:
    14                     list.ToList().ForEach(i =>
    15                     {
    16                         Tuple<string, object[]> sql = CreateInsertSQL(i);
    17                         sqlstr.AppendFormat(sql.Item1, sql.Item2);
    18                     });
    19                     break;
    20                 case SQLType.Update:
    21                     list.ToList().ForEach(i =>
    22                     {
    23                         Tuple<string, object[]> sql = CreateUpdateSQL(i);
    24                         sqlstr.AppendFormat(sql.Item1, sql.Item2);
    25                     });
    26                     break;
    27                 case SQLType.Delete:
    28                     list.ToList().ForEach(i =>
    29                     {
    30                         Tuple<string, object[]> sql = CreateDeleteSQL(i);
    31                         sqlstr.AppendFormat(sql.Item1, sql.Item2);
    32                     });
    33                     break;
    34                 default:
    35                     throw new ArgumentException("请输入正确的参数");
    36             }
    37             return sqlstr.ToString();
    38         }

    代码完成,这个批量操作经过测试,在速度上远远超过EF自带的方法,原因,当然是减少了与数据库交互的次数。

    回到目录

  • 相关阅读:
    1337语言
    BEEF实战全记录
    MySQL字符集编码设置与PHP显示乱码的解决办法
    设置MySql5.5数据库的字符编码为UTF8,解决中文乱码问题
    如何在BeEF中使用metasploit颠覆你的浏览器
    xss窃取cookie测试
    xss测试代码
    'or'='or'经典漏洞代码分析
    mysql注入漏洞测试网页
    ipc$入侵
  • 原文地址:https://www.cnblogs.com/lori/p/2855073.html
Copyright © 2011-2022 走看看