EF架構(gou)~性能(neng)高效的批(pi)量操作(Update篇)
很多時間之長,我寫了EF架構~性能高效的批量操作(Insert篇),而今天我(wo)把(ba)Update篇也寫一(yi)下(xia),這(zhe)對(dui)于批量處(chu)理數(shu)據(ju)很有幫助,它解(jie)決了EF與(yu)linq to sql批量更(geng)新數(shu)據(ju)上(shang)的效(xiao)率問(wen)題。
對于EF架構(gou)中的批(pi)量更新操(cao)作,需要我(wo)們為實體的導航屬(shu)性(xing)進(jin)行(xing)手動的標示,因為EF生(sheng)成的實體中沒有一個特殊的說明,所以,我(wo)們必(bi)須(xu)要告訴系統,哪個屬(shu)性(xing)是(shi)導航屬(shu)性(xing),而導航屬(shu)性(xing)是(shi)我(wo)們不去進(jin)行(xing)update的。
1 /// <summary> 2 /// 屬性的導航屬性 3 /// </summary> 4 public class NavigationAttribute : Attribute 5 { 6 7 }
而(er)對于要進行批(pi)量更新(xin)的實體,我(wo)們需要為(wei)導(dao)航屬(shu)性添加(jia)這個特性
1 public class User 2 { 3 public int UserID { get; set; } 4 [Navigation] 5 public User_Extension User_Extension { get; set; } 6 }
而對(dui)于我們(men)構建批量Update語(yu)句,請看代碼,它需要對(dui)導(dao)航屬(shu)性(xing)進(jin)行過濾
1 /// <summary> 2 /// 構建Update語句串(chuan) 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)) //過濾導航(hang)屬性 21 ).ToArray(); 22 23 //過濾主鍵,航(hang)行(xing)屬(shu)性,狀態屬(shu)性等 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("沒(mei)有任何屬性進(jin)行更(geng)新"); 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 }
而(er)對子類公開的Update方(fang)法,我(wo)們進行了一個(ge)封裝,它(ta)通過操作枚舉(ju)來確實你是(shi)要insert,update還是(shi)delete,看代碼
1 /// <summary> 2 /// 執(zhi)行SQL,根據SQL操作(zuo)的類型 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("請輸(shu)入正確的參數(shu)"); 36 } 37 return sqlstr.ToString(); 38 }