很多年前一直使用Ado.net,后來(lái)慢慢轉(zhuǎn)型到其他的orm,在轉(zhuǎn)型過(guò)程中,有意向?qū)烧叩哪P徒Y(jié)合起來(lái),利用DataTable中的行狀態(tài)完善一些mvc中的數(shù)據(jù)控制作用。現(xiàn)在把它放出來(lái),留個(gè)紀(jì)念。
很多年前,對(duì)Ado.net這塊了解較深,當(dāng)時(shí)公司也有一套框架,將Ado.net做成了ORMapping,所以,當(dāng)時(shí)對(duì)DataTable的操作很是熟練。
DataTable中的行狀態(tài)很好的和界面的數(shù)據(jù)后者操作進(jìn)行了關(guān)聯(lián),比如新增,修改,取消,刪除等,都能在DataTable中的行狀態(tài)對(duì)應(yīng)起來(lái),然后那個(gè)orm框架就自動(dòng)根據(jù)不同的行狀態(tài)生成sql語(yǔ)句,也是比較方便。
后來(lái),技術(shù)一直在進(jìn)步,也使用過(guò)EF,使用過(guò)java移植過(guò)來(lái)的Nhibernate,這樣對(duì)實(shí)體類(lèi)的操作越來(lái)越多,當(dāng)時(shí)就產(chǎn)生了這樣一個(gè)想法,界面綁定DataTable,然后數(shù)據(jù)的變動(dòng)通過(guò)這些新的orm工具持久化起來(lái),于是就做了這個(gè)工具類(lèi)。
代碼
因?yàn)槭枪ぞ哳?lèi),代碼結(jié)構(gòu)比較簡(jiǎn)單。如圖:
![]()
TransformUtil工具類(lèi)主要就3個(gè)方法。
一:ConvertDataTableToModel:
主要將DataTable中改動(dòng)的內(nèi)容同步到實(shí)體類(lèi)集合中
/// <summary> /// 將DB中改動(dòng)的內(nèi)容同步到泛型集合中 /// </summary> /// <typeparam name="T">類(lèi)型</typeparam> /// <param name="source">dt源</param> /// <param name="destinationArray">目標(biāo)Model集合</param> /// <returns></returns> public static bool ConvertDataTableToModel<T>(DataTable source, List<T> destinationArray) where T : class { if (source == null || destinationArray == null || source.PRimaryKey == null || source.PrimaryKey.Count() <= 0) return false; DataTable dtChange = source.GetChanges(); if (dtChange == null) return false; List<string> keys = new List<string>(); foreach (var item in source.PrimaryKey) { keys.Add(item.ColumnName); } return ConvertDataTableToModel(source, destinationArray, keys); }
/// <summary> /// 同步table里改動(dòng)的數(shù)據(jù)到泛型集合里去(新增,修改,刪除) /// </summary> /// <typeparam name="T">類(lèi)型</typeparam> /// <param name="source">dt源</param> /// <param name="destinationArray">目標(biāo)Model集合</param> /// <param name="keyColumnArray">主鍵集合</param> /// <returns></returns> public static bool ConvertDataTableToModel<T>(DataTable source, List<T> destinationArray, List<string> keyColumnArray) where T : class { if (source == null || destinationArray == null || source.Rows.Count == 0 || keyColumnArray == null || keyColumnArray.Count == 0) return false; Type modeType = destinationArray.GetType().GetGenericArguments()[0];//模型類(lèi)型 PropertyInfo[] ppInfoArray = modeType.GetProperties();//公共屬性集合 List<PropertyInfo> listPPInfo = ppInfoArray.ToList();//方便查詢(xún) //關(guān)鍵列 List<PropertyInfo> keyPIArray = listPPInfo.FindAll(x => keyColumnArray.Contains(x.Name)); List<T> listToDelete = new List<T>(); //新增的數(shù)據(jù) DataRow[] drAddArray = source.Select("", "", DataViewRowState.Added); object objItem = modeType.Assembly.CreateInstance(modeType.FullName); foreach (DataRow dr in drAddArray) { destinationArray.Add((T)objItem); foreach (System.Reflection.PropertyInfo pi in listPPInfo) { pi.SetValue(destinationArray[destinationArray.Count - 1], dr[pi.Name], null); } } //修改和刪除的數(shù)據(jù) DataView dvForOP = new DataView(source); dvForOP.RowStateFilter = DataViewRowState.Deleted | DataViewRowState.ModifiedCurrent; foreach (DataRowView drv in dvForOP) { for (int i = 0; i < destinationArray.Count; i++) { bool blIsTheRow = true; //找出關(guān)鍵列對(duì)應(yīng)的行 foreach (System.Reflection.PropertyInfo pInfo in keyPIArray) { object okey = pInfo.GetValue(destinationArray[i], null); if (okey == null) continue; if (drv[pInfo.Name].ToString() != okey.ToString()) { blIsTheRow = false; break; } } if (!blIsTheRow)//非本行 continue; //根據(jù)行狀態(tài)同步賦值 switch (drv.Row.RowState) { case DataRowState.Modified: { foreach (System.Reflection.PropertyInfo pi in listPPInfo) { if (keyPIArray.Contains(pi))//主鍵列不更新 continue; pi.SetValue(destinationArray[i], drv[pi.Name], null); } } break; case DataRowState.Deleted: { listToDelete.Add(destinationArray[i]); } break; } } } for (int i = 0; i < listToDelete.Count; i++) { destinationArray.Remove(listToDelete[i]); } return true; }
三:ConvertModelToDataTable:
將實(shí)體類(lèi)集合轉(zhuǎn)成DataTable。其中params這個(gè)參數(shù)比較有意思,大家可以去查下。
/// <summary> /// 將泛型集合類(lèi)轉(zhuǎn)換成DataTable /// </summary> /// <typeparam name="T">集合項(xiàng)類(lèi)型</typeparam> /// <param name="sourceArray">集合</param> /// <param name="propertyNameArray">需要返回的列的列名,如需返回所有列,此參數(shù)傳入null值</param> /// <returns>數(shù)據(jù)集(表)</returns> public static DataTable ConvertModelToDataTable<T>(IList<T> sourceArray, params string[] propertyNameArray) where T:class { List<string> propertyNameList = new List<string>(); if (propertyNameArray != null) propertyNameList.AddRange(propertyNameArray); DataTable result = new DataTable(); //獲取結(jié)構(gòu) Type[] typeArr = sourceArray.GetType().GetGenericArguments(); if (typeArr.Length == 0) return result; PropertyInfo[] propertys = typeArr[0].GetProperties(); foreach (PropertyInfo pi in propertys) { if (propertyNameList.Count == 0) { result.Columns.Add(pi.Name, pi.PropertyType); } else { if (propertyNameList.Contains(pi.Name)) result.Columns.Add(pi.Name, pi.PropertyType); } } for (int i = 0; i < sourceArray.Count; i++) { ArrayList tempList = new ArrayList(); foreach (PropertyInfo pi in propertys) { if (propertyNameList.Count == 0) { object obj = pi.GetValue(sourceArray[i], null); tempList.Add(obj); } else { if (propertyNameList.Contains(pi.Name)) { object obj = pi.GetValue(sourceArray[i], null); tempList.Add(obj); } } } object[] array = tempList.ToArray(); result.LoadDataRow(array, true); } return result; }
四:ConvertDataViewToModel:
將Dataview中所以?xún)?nèi)容轉(zhuǎn)成實(shí)體。
/// <summary> /// 將視圖轉(zhuǎn)換成泛型集合 /// </summary> /// <typeparam name="T">類(lèi)型</typeparam> /// <param name="dataView">視圖</param> /// <param name="model">泛型實(shí)例</param> /// <returns></returns> public static List<T> ConvertDataViewToModel<T>(DataView dataView, T model) where T:class { List<T> listReturn = new List<T>(); Type modelType = model.GetType(); DataTable dt = dataView.Table; //獲取model所有類(lèi)型 PropertyInfo[] modelProperties = modelType.GetProperties(); //遍歷所有行,逐行添加對(duì)象 for (int i = 0; i < dt.Rows.Count; i++) { object obj = modelType.Assembly.CreateInstance(modelType.FullName); listReturn.Add((T)obj); //遍歷model所有屬性 foreach (PropertyInfo pi in modelProperties) { //遍歷所有列 foreach (DataColumn col in dt.Columns) { //如果列數(shù)據(jù)類(lèi)型與model的數(shù)據(jù)類(lèi)型相同、名稱(chēng)相同 if (col.DataType == pi.PropertyType && col.ColumnName == pi.Name) { pi.SetValue(obj, dt.Rows[i][col.ColumnName], null); } } } } return listReturn; }
這次的UntTest比較簡(jiǎn)單,覆蓋率也不是100%,都快12點(diǎn)了,得休息了,就簡(jiǎn)單的弄了2個(gè)測(cè)試方法。如下:
[TestMethod] public void TestConvertDataTableToModel() { DataTable dt = new DataTable(); dt.Columns.Add("Id", typeof(string)); dt.Columns.Add("Name", typeof(string)); dt.Columns.Add("Address", typeof(string)); dt.PrimaryKey = new DataColumn[] { dt.Columns[0] }; dt.Rows.Add("0001", "張三", "武漢市"); dt.Rows.Add("0002", "李四", "北京市"); dt.AcceptChanges(); dt.Rows.Add("0003", "王五", "深圳市"); List<People> allPeople = new List<People>(); TransformUtil.ConvertDataTableToModel<People>(dt, allPeople); //斷言是不是只有一個(gè)數(shù)據(jù),平且是只是修改狀態(tài)的王五這個(gè)人 Assert.AreEqual(allPeople.Count, 1); Assert.AreEqual(allPeople[0].Name, "王五"); }
[TestMethod] public void TestConvertModelToDataTable() { List<People> allPeople = new List<People>() { new People(){ Id="0001", Name="張三", Address ="武漢市"}, new People(){ Id="0002", Name="李四", Address ="北京市"}, new People(){ Id="0003", Name="王五", Address ="深圳市"} }; DataTable dt = TransformUtil.ConvertModelToDataTable<People>(allPeople, null); //斷言是不是有3行數(shù)據(jù),數(shù)據(jù)的列有3列,第1列是不是Id,第一行第二列是不是張三 Assert.AreEqual(dt.Rows.Count, 3); Assert.AreEqual(dt.Columns.Count, 3); Assert.AreEqual(dt.Columns[0].ColumnName, "Id"); Assert.AreEqual(dt.Rows[0][1], "張三"); } }
測(cè)試結(jié)果如下:
兩個(gè)測(cè)試用例均通過(guò)。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注