将不确定变为确定系列~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

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

回到目录

posted @ 2012-09-22 23:18  张占岭  阅读(1290)  评论(2编辑  收藏  举报