無論是Linq To SQL還是Linq To Object(Entity frameworks)它們都為開發人員提供了Insert操作,及Insert集合操作,即InsertOnSubmit和InsertAllOnSubmit,前者是將一個實體標記為一個插入狀態,而后都是將一個集合標記為插入狀態,...
無論是Linq To SQL還是Linq To Object(Entity frameworks)它們都為開發人員提供了Insert操作,及Insert集合操作,即InsertOnSubmit和InsertAllOnSubmit,前者是將一個實體標記為一個插入狀態,而后都是將一個集合標記為插入狀態,而當前進行這兩種操作時,你並沒有與數據庫進行連接,這就是LINQ提倡的延時加載,那它們什么時候與數據庫進行真正的交互呢,實現上,實驗表明,是在觸發SubmitChanges方法時,才會真實與數據庫進行操作,這是正常的,也沒有什么可以說的。
而今天我主要說的就是,當我們進行批量插入時,用linq給我們提供的InsertAllOnSubmit方法是否可以實現我們的操作,如果實現了,那是否是我們能夠接受的方式,我們在做一個實驗吧
一個列表:
1
2
3
4
5
6
7
8
9
|
List userList=
new
List();
for
(
int
i=0;i<100000;i++)
{
userList.Add(
new
User{Name=
"zzl"
+i});
}
_db.InsertAllOnSubmit(userList);
_db.SubmitChanges();
|
結果怎么樣呢?經過我的觀察,結果是正確的,10萬條數據可以插入到數據庫中,LINQ確實是幫助我們完成了列表的插入工作,但過程我們是否可以接受?
可以肯定的說,不可以,而且是非常不可以,對於這個插入操作,它對數據服務器的壓力是驚人的,它建立“鏈接”次為10萬次,即每個Insert語句就建立一個鏈接,這是我們不能接受的,所以,LINQ的批量操作確實靠不住。
OK,既然LINQ的方式是不可取的,那我們只好自己去動手寫了,呵呵,我們的思想去將10條Insert合並在一起,一次性發給服務器,一次性執行,對於目前的網絡帶寬這10條數據不成問題,呵呵。
一 單個實體的Insert,我們采用LINQ的延時插入方式:
1
2
3
4
5
|
public
virtual
void
Insert(TEntity entity)
where
TEntity :
class
{
DB.GetTable().InsertOnSubmit(entity);
this
.SubmitChanges();
}
|
二 批量插入實體,我們采用拼接字符串,並向數據服務器發命令的方式,這個也是我比較滿足的作品,它是一個通用的方式,並且不需要修改原來插入代碼,它的
方法簽名是一個列表,這樣做是正確的,對於程序員來說是非常友好的。
先看之前的LINQ批量插入:
public virtual void Insert(IEnumerable list) where TEntity : class
{
DB.GetTable().InsertAllOnSubmit(list);
this.SubmitChanges();
}
而在我們修改后,方法簽名是不變的,所以原來調用它的方法,不需要進行修改:
1 ///
2 /// ADO優化的批量添加
3 ///
4 ///
5 ///
6 public virtual void Insert
7 {
8 this.InsertForADO(list);
9 }
所需要的輔助方法:
1 #region LINQ調用T-SQL實現批量添加
2 ///
3 /// 得到數據庫表或視圖的抽象
4 ///
5 ///
6 ///
7 MetaTable GetMetaTable(Type rowType)
8 {
9 return DB.Mapping.GetTable(rowType);
10 }
11
12 ///
13 /// 建立SQL語句
14 ///
15 ///
16 ///
17 Tuple<string,> CreateInsertArguments(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 arguments = new List();
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,>(fieldbuilder.ToString(), arguments.ToArray());
65 }
66
67 void InsertForADO(IEnumerable list)
68 {
69 StringBuilder sqlstr = new StringBuilder();
70 list.ToList().ForEach(i =>
71 {
72 Tuple<string,> insert = CreateInsertArguments(i);
73 sqlstr.AppendFormat(insert.Item1, insert.Item2);
74 });
75 DB.ExecuteCommand(sqlstr.ToString());
76 }
77
78 #endregion