咱們一般使用update語句更新數據庫記錄,例如使用update user set username='001', nickname='Tom', age=18 where id = 1語句更新username、nickname或age字段的值。假設,咱們只修改了username,並無修改nickname和age,那麼上面的 sql就顯得多餘了,改爲update user set username='001' where id = 1纔算完美,即哪些字段發生了變化就更新哪些字段。html
此外,SQL Server數據庫中有觸發器,可監控到字段值的變動,例如在表user上建立觸發器sql
create trigger [dbo].[tr_user_update] on [dbo].[user] After update as declare @id int; select @id = id from inserted; if update(nickname) begin --some code end;
若是使用update user set username='001', nickname='Tom', age=18 where id = 1語句,即使nickname和age的值與數據庫中徹底同樣,也會觸發 some code,但這並非咱們指望的。數據庫
因此執行update更新前,有必要檢查哪些字段需發生了修改,尤爲是須要記錄表變動歷史的情形。本例中,筆者使用System.Reflection.PropertyInfo和DataRow檢查發生更新的字段,並拼接要更新的Update SQL語句。函數
首先,按照表user建立User.cs類ui
class User { // 參照用戶表User的字段定義屬性 // 不包括系統字段 // 僅包括用戶會修改的字段 // 屬性名必須和字段名一致 public string UserName { get; set; } public string NickName { get; set; } public string Password { get; set; } public string Email { get; set; } public string Phone { get; set; } public int Age { get; set; } }
其次,建立賦值函數InitEntity(DataRow, Obj)spa
public static Obj InitEntity<Obj>(System.Data.DataRow row, Obj entity) where Obj : new() { if (entity == null) entity = new Obj(); // 取得entity的類型 Type type = typeof(Obj); // 取得entity的屬性 System.Reflection.PropertyInfo[] props = type.GetProperties(); // 遍歷entity屬性集合,按照屬性類型給其賦值。經過entity屬性名從row中取得對應的值。 foreach (System.Reflection.PropertyInfo prop in props) { if (prop.PropertyType.FullName.Equals("System.Int32")) { prop.SetValue(entity , Convert.ChangeType(MyFuncLib.dtv(row, prop.Name, "0") , prop.PropertyType), null); } else if (prop.PropertyType.FullName.Equals("System.Decimal")) { prop.SetValue(entity , Convert.ChangeType(MyFuncLib.dtv(row, prop.Name, "0") , prop.PropertyType), null); } else if (prop.PropertyType.FullName.Equals("System.Double")) { prop.SetValue(entity , Convert.ChangeType(MyFuncLib.dtv(row, prop.Name, "0") , prop.PropertyType), null); } else if (prop.PropertyType.FullName.Equals("System.Boolean")) { prop.SetValue(entity , Convert.ChangeType(MyFuncLib.dtv(row, prop.Name, "false") , prop.PropertyType), null); } else if (prop.PropertyType.FullName.Equals("System.DateTime")) { if (MyFuncLib.dtv(row, prop.Name, null) != null) { prop.SetValue(entity , Convert.ChangeType(MyFuncLib.dtv(row, prop.Name, null) , prop.PropertyType), null); } } else { prop.SetValue(entity , MyFuncLib.dtv(row, prop.Name, string.Empty), null); } } return entity; }
顯示用戶數據時,將數據保存在一個DataTable dt中日誌
private void Form1_Load(object sender, EventArgs e) { // 初始化表時,讀取數據 SqlConnection conn = new SqlConnection(); conn.ConnectionString = ""; conn.Open(); SqlDataAdapter adapter = new SqlDataAdapter(); adapter.SelectCommand.CommandText = "select * from user where id = 1"; adapter.Fill(dt); adapter = null; conn.Close(); }
修改數據後,將變動存入dt的第一條記錄newRow中。保存數據前從數據庫中讀取記錄存入oldRow,而後比較oldRow和newRow差別,遇到差別時拼接Update SQL語句。code
private void btnSave_Click(object sender, EventArgs e) { // 理論上只有一條記錄值 if (dt.Rows.Count > 0) { // 模擬數據修改,直接修改dt.Rows[0] #region update row dt.Rows[0]["UserName"] = "001"; dt.Rows[0]["NickName"] = "Tom"; dt.Rows[0]["Password"] = "123456"; #endregion // 打開數據庫 SqlConnection conn = new SqlConnection(); conn.ConnectionString = ""; conn.Open(); // 修改前讀取數據庫中的記錄 DataTable dtTemp = new DataTable(); SqlDataAdapter adapter = new SqlDataAdapter(); adapter.SelectCommand.CommandText = "select * from user where id = 1"; adapter.Fill(dtTemp); DataRow oldRow = dtTemp.Rows[0]; adapter = null; // 當前數據庫中的值 User oldItem = MyFuncLib.InitEntity(oldRow, new User()); // 可能已經發生修改的值 User newItem = MyFuncLib.InitEntity(dt.Rows[0], new User()); // 標識當前記錄是否發生了修改 bool amended = false; // Update Sql StringBuilder sql = new StringBuilder(); sql.AppendLine("update user set modifiedDate = getDate()"); // 定義Update Command SqlCommand comdUpdate = new SqlCommand(); // 遍歷User類屬性 System.Reflection.PropertyInfo[] props = typeof(User).GetProperties(); foreach (System.Reflection.PropertyInfo prop in props) { // 排除id等系統字段 if (!prop.Name.Equals("id")) { // 僅當值發生修改時才拼接SQL語句 if (!prop.GetValue(oldItem, null).Equals(prop.GetValue(newItem, null))) { // 拼接Update語句 sql.AppendLine(string.Format(",[{0}] = @{0}", prop.Name)); // 同時添加參數 comdUpdate.Parameters.AddWithValue( string.Format("@{0}", prop.Name) , prop.GetValue(newItem, null).ToString()); // 只要有一個字段值發生了變化,就設置amended = true amended = true; // 此處可插入日誌代碼,用於對當前表變動歷史的記錄 } } } if (amended) { // 執行拼接的Update Sql comdUpdate.CommandText = sql.ToString(); comdUpdate.Connection = conn; comdUpdate.ExecuteNonQuery(); } // 關閉SQL鏈接 conn.Close(); } }
演示示例:下載orm