• 将不确定变为确定系列~Linq的批量操作靠的住吗?


    回到目录     

    无论是Linq To SQL还是Linq To Object(Entity frameworks)它们都为开发人员提供了Insert操作,及Insert集合操作,即InsertOnSubmit和InsertAllOnSubmit,前者是将一个实体标记为一个插入状态,而后都是将一个集合标记为插入状态,而当前进行这两种操作时,你并没有与数据库进行连接,这就是LINQ提倡的延时加载,那它们什么时候与数据库进行真正的交互呢,实现上,实验表明,是在触发SubmitChanges方法时,才会真实与数据库进行操作,这是正常的,也没有什么可以说的。

          而今天我主要说的就是,当我们进行批量插入时,用linq给我们提供的InsertAllOnSubmit方法是否可以实现我们的操作,如果实现了,那是否是我们能够接受的方式,我们在做一个实验吧

    一个列表:

    1 List<User> userList=new List<User>();
    2 
    3 for(int i=0;i<100000;i++)
    4 {
    5   userList.Add(new User{Name="zzl"+i});
    6 }
    7 _db.InsertAllOnSubmit(userList);
    8 
    9 _db.SubmitChanges();


    结果怎么样呢?经过我的观察,结果是正确的,10万条数据可以插入到数据库中,LINQ确实是帮助我们完成了列表的插入工作,但过程我们是否可以接受?

    可以肯定的说,不可以,而且是非常不可以,对于这个插入操作,它对数据服务器的压力是惊人的,它建立“链接”次为10万次,即每个Insert语句就建立一个链接,这是我们不能接受的,所以,LINQ的批量操作确实靠不住。

    OK,既然LINQ的方式是不可取的,那我们只好自己去动手写了,呵呵,我们的思想去将10条Insert合并在一起,一次性发给服务器,一次性执行,对于目前的网络带宽这10条数据不成问题,呵呵。

    一 单个实体的Insert,我们采用LINQ的延时插入方式:

    1  public virtual void Insert<TEntity>(TEntity entity) where TEntity : class
    2         {
    3             DB.GetTable<TEntity>().InsertOnSubmit(entity);
    4             this.SubmitChanges();
    5         }

    二 批量插入实体,我们采用拼接字符串,并向数据服务器发命令的方式,这个也是我比较满足的作品,它是一个通用的方式,并且不需要修改原来插入代码,它的

    方法签名是一个列表,这样做是正确的,对于程序员来说是非常友好的。

    先看之前的LINQ批量插入:

     public virtual void Insert<TEntity>(IEnumerable<TEntity> list) where TEntity : class
            {
                DB.GetTable<TEntity>().InsertAllOnSubmit(list);
                this.SubmitChanges();
            }

    而在我们修改后,方法签名是不变的,所以原来调用它的方法,不需要进行修改:

    1         /// <summary>
    2         /// ADO优化的批量添加
    3         /// </summary>
    4         /// <typeparam name="TEntity"></typeparam>
    5         /// <param name="list"></param>
    6         public virtual void Insert<TEntity>(IEnumerable<TEntity> list) where TEntity : class
    7         {
    8             this.InsertForADO<TEntity>(list);
    9         }

    所需要的辅助方法:

     1 #region LINQ调用T-SQL实现批量添加
     2         /// <summary>
     3         /// 得到数据库表或视图的抽象
     4         /// </summary>
     5         /// <param name="rowType"></param>
     6         /// <returns></returns>
     7         MetaTable GetMetaTable(Type rowType)
     8         {
     9             return DB.Mapping.GetTable(rowType);
    10         }
    11 
    12         /// <summary>
    13         /// 建立SQL语句
    14         /// </summary>
    15         /// <param name="entity"></param>
    16         /// <returns></returns>
    17         Tuple<string, object[]> CreateInsertArguments<TEntity>(TEntity entity)
    18         {
    19             if (entity == null)
    20                 throw new ArgumentException("The database entity can not be null.");
    21 
    22             Type entityType = entity.GetType();
    23             MetaTable table = GetMetaTable(entityType);
    24             MetaDataMember identityDatamember = table.RowType.DBGeneratedIdentityMember;
    25 
    26             List<object> arguments = new List<object>();
    27             StringBuilder fieldbuilder = new StringBuilder();
    28             StringBuilder valuebuilder = new StringBuilder();
    29 
    30             fieldbuilder.Append("INSERT INTO " + table.TableName + " (");
    31 
    32             foreach (var member in table.RowType.PersistentDataMembers)
    33             {
    34 
    35                 if (!member.IsAssociation && !member.IsDbGenerated)
    36                 {
    37                     object value = entityType.GetProperty(member.Name).GetValue(entity, null);
    38                     if (value != null)
    39                     {
    40                         if (arguments.Count != 0)
    41                         {
    42                             fieldbuilder.Append(", ");
    43                             valuebuilder.Append(", ");
    44                         }
    45 
    46                         fieldbuilder.Append(member.MappedName);
    47                         if (member.Type == typeof(string) || member.Type == typeof(DateTime))
    48                             valuebuilder.Append("'{" + arguments.Count + "}'");
    49                         else
    50                             valuebuilder.Append("{" + arguments.Count + "}");
    51                         if (value.GetType() == typeof(string))
    52                             value = value.ToString().Replace("'", "char(39)");
    53                         arguments.Add(value);
    54 
    55                     }
    56                 }
    57             }
    58 
    59 
    60             fieldbuilder.Append(") Values (");
    61 
    62             fieldbuilder.Append(valuebuilder.ToString());
    63             fieldbuilder.Append(");");
    64             return new Tuple<string, object[]>(fieldbuilder.ToString(), arguments.ToArray());
    65         }
    66 
    67         void InsertForADO<TEntity>(IEnumerable<TEntity> list)
    68         {
    69             StringBuilder sqlstr = new StringBuilder();
    70             list.ToList().ForEach(i =>
    71             {
    72                 Tuple<string, object[]> insert = CreateInsertArguments(i);
    73                 sqlstr.AppendFormat(insert.Item1, insert.Item2);
    74             });
    75             DB.ExecuteCommand(sqlstr.ToString());
    76         }
    77 
    78         #endregion

    接下来的时间,我将会继续写一个批量更新和批量删除,敬请收看,呵呵。

    回到目录

  • 相关阅读:
    sort_action
    jedis
    ClassNotFoundException
    mysql-test-run.pl
    mysql 5.6 bug
    The basic principle of test case 修改引擎
    mysql 执行计划走索引
    mysql 执行计划走索引
    14.1.2 Checking InnoDB Availability 检查InnoDB 可用性:
    14.1.2 Checking InnoDB Availability 检查InnoDB 可用性:
  • 原文地址:https://www.cnblogs.com/lori/p/2698558.html
Copyright © 2020-2023  润新知