將不(bu)確(que)定(ding)變為確(que)定(ding)系列~Linq的批(pi)量(liang)操作靠的住(zhu)嗎?
無論(lun)是(shi)Linq To SQL還是(shi)Linq To Object(Entity frameworks)它們(men)都為(wei)開(kai)發(fa)人員提供了(le)Insert操(cao)作,及Insert集合操(cao)作,即InsertOnSubmit和InsertAllOnSubmit,前者是(shi)將一個實體(ti)標記(ji)為(wei)一個插入狀態(tai)(tai),而后都是(shi)將一個集合標記(ji)為(wei)插入狀態(tai)(tai),而當前進(jin)(jin)行(xing)(xing)這(zhe)兩(liang)種操(cao)作時(shi),你并沒有與(yu)(yu)數據(ju)庫(ku)進(jin)(jin)行(xing)(xing)連接,這(zhe)就是(shi)LINQ提倡的(de)(de)(de)延(yan)時(shi)加載,那它們(men)什(shen)么(me)時(shi)候(hou)與(yu)(yu)數據(ju)庫(ku)進(jin)(jin)行(xing)(xing)真(zhen)正的(de)(de)(de)交互呢(ni),實現上,實驗表明,是(shi)在觸發(fa)SubmitChanges方法時(shi),才會真(zhen)實與(yu)(yu)數據(ju)庫(ku)進(jin)(jin)行(xing)(xing)操(cao)作,這(zhe)是(shi)正常的(de)(de)(de),也(ye)沒有什(shen)么(me)可以(yi)說的(de)(de)(de)。
而今(jin)天(tian)我(wo)(wo)主(zhu)要說的(de)就是(shi),當我(wo)(wo)們(men)進行(xing)批量(liang)插(cha)入時,用linq給我(wo)(wo)們(men)提供的(de)InsertAllOnSubmit方法是(shi)否可以實(shi)(shi)現我(wo)(wo)們(men)的(de)操(cao)作,如果(guo)實(shi)(shi)現了,那是(shi)否是(shi)我(wo)(wo)們(men)能夠接受(shou)的(de)方式,我(wo)(wo)們(men)在(zai)做一個(ge)實(shi)(shi)驗吧
一個列表:
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();
結果怎么樣呢?經過我的(de)觀察,結果是(shi)正確的(de),10萬條數據可以插入(ru)到數據庫中,LINQ確實是(shi)幫助我們完成了列表的(de)插入(ru)工作,但(dan)過程我們是(shi)否可以接受?
可以肯定的說,不可以,而且是非常不可以,對于這個插入操作,它對數據服務器的壓力是驚人的,它建立“鏈接”次為10萬次,即每個Insert語句就建立一個鏈接,這是我們不能接受的,所以,LINQ的批量操作確實靠不住。
OK,既(ji)然LINQ的方式是不(bu)可取(qu)的,那我們只好自(zi)己去動手寫(xie)了,呵呵,我們的思想(xiang)去將(jiang)10條Insert合并在一起,一次性發給服務器,一次性執行,對于目前(qian)的網絡帶(dai)寬這(zhe)10條數據不(bu)成(cheng)問題,呵呵。
一 單個實體的(de)Insert,我們采用LINQ的(de)延時(shi)插入方(fang)式:
1 public virtual void Insert<TEntity>(TEntity entity) where TEntity : class 2 { 3 DB.GetTable<TEntity>().InsertOnSubmit(entity); 4 this.SubmitChanges(); 5 }
二 批量插入實體,我(wo)們采用拼接字符串,并向數(shu)據服務(wu)器發命令的方式,這(zhe)個也是我(wo)比(bi)較(jiao)滿(man)足的作品,它(ta)是一(yi)個通用的方式,并且不需(xu)要(yao)修(xiu)改原來插入代(dai)碼,它(ta)的
方法(fa)簽名是(shi)(shi)一個列(lie)表(biao),這樣做是(shi)(shi)正(zheng)確的(de),對于程序員來說是(shi)(shi)非常友(you)好(hao)的(de)。
先看之前(qian)的LINQ批量(liang)插入:
public virtual void Insert<TEntity>(IEnumerable<TEntity> list) where TEntity : class { DB.GetTable<TEntity>().InsertAllOnSubmit(list); this.SubmitChanges(); }
而(er)在我們(men)修改后(hou),方(fang)法簽名(ming)是(shi)不(bu)變的,所以(yi)原來調(diao)用它(ta)的方(fang)法,不(bu)需(xu)要進行(xing)修改:
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 /// 建(jian)立(li)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
接下來(lai)的時間,我將會繼續寫(xie)一個批量更(geng)新和批量刪除,敬請收(shou)看(kan),呵(he)呵(he)。