zoukankan      html  css  js  c++  java
  • DataGridView编辑后立即更新到数据库的两种方法

    https://blog.csdn.net/update7/article/details/80066231

    DataGridView控件是微软预先写好的一个显示数据的控件,功能非常强大,可以显示来自数据库表的数据和XML等其他来源的数据。最近在做一个迷你超市管理系统,要大量用到这个控件。所以花时间好好研究了下。

    这是迷你超市管理系的库存数据DataGridView,用户一定会想如果能直接在DGV中修改数据就好了。

    是的,这是一个很好的想法,这个功能微软早就帮我们想到了,现在可以使两种方法加以实现。下面就来介绍一下他们。

    第一张方法:基于DataAdapter对象创建一个CommandBulider,用来生成Sql命令,修改数据源,从而直接更改数据表的内容。

      前提是:

        1.这个表必须有主键,否则该对象无法生成Update和delete、insert的Sql命令,报异常:

         对于不返回任何键列信息的 SelectCommand,不支持 UpdateCommand 的动态 SQL 生成。

        2.实例化SqlCommandBuilder对象的数据适配器对象SqlDataAdapter必须预先设置好SelectCommand属性

        3.更新的表中不能包括image类型的字段(列)

      由于出错的情况有很多,程序员无法完全掌握,所以我们强烈建议将更新代码写在try catch里

     下面是此方法的实例:

     /// <summary>
            /// 数据适配器
            /// </summary>
            SqlDataAdapter adapter = null;
            /// <summary>
            /// 数据集对象
            /// </summary>
            DataSet dSet = null;
    
            /// <summary>
            /// 连接字符串
            /// </summary>
            private static string strConn = "server=.\sqlexpress;database=MySchool;uid=sa;pwd=123456";
    
            /// <summary>
            /// 窗体加载事件
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void Form3_Load(object sender, EventArgs e)
            {
                adapter = new SqlDataAdapter("select * from UserInfo", strConn);
                dSet = new DataSet();
                adapter.Fill(dSet);
    
                DGVMain.DataSource = dSet.Tables[0];
            }
    
            /// <summary>
            /// 更新按钮点击事件
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void button1_Click(object sender, EventArgs e)
            {
                //创建命令重建对象
                SqlCommandBuilder scb = new SqlCommandBuilder(adapter);
    
                //更新数据
                try
                {
             //这里是关键
                    adapter.Update(dSet);
                }
                catch (SqlException ex)
                {
                    MessageBox.Show(ex.Message);
                }
    
            }
    

      

    由于各种原因,性能问题,安全问题和其他复杂的因素。

    主要缺点:

    1、 基于单表,只能对一个数据源表进行更新,如果要更新数据库
    中的已改变的表,则不能用它来更新了。 

    2、 要求数据库中必须设置好主键字段 

    3、 不能对存有图片的数据库进行增删改操作 

    4、 执行起来,速度相对于非自动化慢(当然,是在数据库的规模
    很大的情况下)

    需要注意的地方:

    1、 必须与DataAdapter结合使用 
    2、 实例化SqlCommandBuilder对象前,必须先指定好数据适配器
    的填充命令(SelectCommand)。 
    3、 填充命令(Select 语句)中返回的列要包括主键列,否则将无
    法产生Update,和Delete语句。 
    4、  使用命令构建器比手动编写SQL更好,但是它们只能处理一个
    表,底层的数据库表必须有主键或唯一键。另外,数据适配器的SelectCommand属性必须有一个包含主键的查询。

    这种方法在实际项目中根本不会用到,一些小项目和初学者可以尝试。

    第二种方法:定位被修改的单元格,获取列名和id,构建SQL然后,然后执行更新操作。

      这种方法比第一张方法复杂多,效果却是一样的,一般也不太会去用。这里简单介绍一下。思路是:点击单元格触发DGV的CellBeginEdit事件,在此事件中保存原先的值到成员字段中,然后在DGV的CellEndEdit事件中修改数据,执行更新。

      具体的代码:

    #region DGV直接编辑修改数据的功能
            /// <summary>
            /// 用来存放DGV单元格修改之前值
            /// </summary>
            Object cellTempValue = null;
    
            /// <summary>
            /// DGV单元格开始编辑时触发的事件
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void DGVMain_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
            {
                cellTempValue = DGVMain.Rows[e.RowIndex].Cells[e.ColumnIndex].Value;
            }
    
            /// <summary>
            /// DGV单元格结束编辑时触发的事件
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void DGVMain_CellEndEdit(object sender, DataGridViewCellEventArgs e)
            {
                //判断编辑前后的值是否一样(是否修改了内容)
                if (Object.Equals(cellTempValue, DGVMain.Rows[e.RowIndex].Cells[e.ColumnIndex].Value))
                {
                    //如果没有修改,则返回
                    return;
                }
    
                //判断用户是否确定修改
                if (MessageBox.Show("确定修改?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.None) != DialogResult.OK)
                {
                    //如果不修改,恢复原来的值
                    DGVMain.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = cellTempValue;
                    return;
                }
    
                //修改数据库的数据
                string sql = String.Format("update  set {1}='{2}' where 商品编号='{3}'",
                    DGVMain.Columns[0].DataPropertyName,            //所选单元格列名
                    DGVMain.Rows[e.RowIndex].Cells[e.ColumnIndex].Value,    //所选单元格修改后的值
                    DGVMain.Rows[e.RowIndex].Cells[0].Value                  //所选行的商品编号
                );
    
                try
                {
                    OleDbHelper.ExecuteNonQuery(CommandType.Text, sql);
                }
                catch (OleDbException ex)
                {
                    MessageBox.Show(ex.Message);
                }
    
                //刷新数据
                LoadDGV();
            } 
            #endregion
    

      

    个人建议的解决方案:做一个ContextMenu菜单,绑定DGV,菜单中有修改数据和删除数据,当用户选择整行后,点击右键选择修改信息,立即弹出一个窗口,根据该行的id重新从数据库中取出该行记录的所有值,赋值到各个文本框中,然后点击更新,执行更新操作。这是最最纯洁的方法。

  • 相关阅读:
    C# 截取窗口图像(包括遮挡窗口,最小化窗口)
    C# 自定义DevExpress中XtraMessageBox的窗口Icon
    C# DevExpress的皮肤,没有在多线程中应用
    DevExpress的RibbonForm在WIN7下标题栏透明,没应用程序设置的Skin
    C# RibbonForm的标题Text显示不完全的解决方法
    C# 使用递归获取文件路径,不获取拒绝访问的文件夹
    socket使用
    KMP模板
    HDU1358(KMP)
    windows环境变量
  • 原文地址:https://www.cnblogs.com/wfy680/p/12723928.html
Copyright © 2011-2022 走看看