如何自动拼接 Update语句,仅Update已修改的字段

来源:互联网 发布:ubuntu卸载nvidia驱动 编辑:程序博客网 时间:2024/06/10 23:50

我们通常使用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才算完美,即哪些字段发生了变化就更新哪些字段。

此外,SQL Server数据库中有触发器,可监控到字段值的变更,例如在表user上创建触发器

create trigger [dbo].[tr_user_update]on [dbo].[user]Afterupdateasdeclare @id int;select @id = id from inserted;if update(nickname) begin--some codeend;

如果使用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类

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)

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语句。

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();    }}

演示示例:下载

0 0