DataGridView有外键时,如何用SqlCommandBuilder

制作时间:2009/9/10 17:00---2009/9/15 12:24

重点:
  1.DataGridView里加入DataGridViewComboBoxColumn(并把原来的列隐藏,主要是不知道如何把某列设为ComboBox)
     1.先绑定ComboBox
     2.将DataGridViewComboBoxColumn加到DataGridView,并设置DataPropertyName

            dgvCol = new DataGridViewComboBoxColumn();
            dgvCol.DataSource = ds.Tables["Class"];
            dgvCol.DisplayMember = "Name";
            dgvCol.ValueMember = "Id";
            dgvCol.DisplayStyle = DataGridViewComboBoxDisplayStyle.Nothing;

            dgvStu_Class.Columns.Add(dgvCol);
            dgvCol.DataPropertyName = "ClassId";
            dgvCol.DisplayIndex = 2;
            dgvCol.HeaderText = "班级";

           
   2.以上的好处,就是可以把外键用ComboBox显示,而且更新可以用SqlCommandBuilder

 


要求:
1.新建数据库dgvManyTable,表Student 字段Id Name ClassId(外键)
                         表Class 字段Id Name
2.用DataGridView显示姓名和班级
3.在DataGridView里可以增删改多行数据,并更新到数据库


分析:
   1.由于设计到2张表,可以通过级联查询(姓名,和班级名),然后绑定到DataGridView
      更新到数据库时,不能用SqlCommandBuilder,所以选择sql带参数的形式:
          1.写sql语句带参数
          2.给参数赋值,并添加到SqlCommand.Parametes
          3.给da配SqlCommand,da.InsertCommand,da.UpdateCommand
   2.可以用类似.net中的 GirdView,在外键的那列加一个ComboBox(绑定Class表)
      有2个好处:
         1.修改数据时,不需要用到级联,可以用SqlCommandBuilder自动配参数
         2.班级的那列由于绑定了Class表,可以约束用户的输入
      

代码实现:
   对应上面的分析
      1.DgvUpdateForm(级联查询,用到了SqlParameter给每个字段配参数)
      2.DgvUpdate_1Form(类似GirdView,外键列用ComboBox绑定表,可以用到SqlCommandBuilder)
         手段:创建一个DataGridViewComboBoxColumn,指定数据源和DataPropertyName后,添加到DataGridView

 

  DgvUpdateForm(级联查询,用到了SqlParameter给每个字段配参数) 
======================================
1.从数据库查数据填充dgv
        private void DgvUpdateForm_Load(object sender, EventArgs e)
        {
            string sql = "select s.Id,s.Name,c.Name as ClassName from Student s,
                          Class c where s.ClassId= c.Id";
            try
            {
                da = new SqlDataAdapter(sql, DBHelper.conn);
                da.Fill(ds, "Student");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                MessageBox.Show("数据库操作出错!");
            }
           
            dgvStu_Class.DataSource = ds.Tables["Student"];
        }


2.在dgv上修改后,更新到数据库(因为是级联表,所以不能用sqlCommandBuilder)
  1.最初
        private void btnAdd_Click(object sender, EventArgs e)
        {
  //插入数据的sql语句,先通过dgv的班级名称查得ClassId,然后插入到表Student
            string sql = "Declare @ClassId int Select @ClassId = Id from Class where Name=@ClassName"
                          +" insert Student values(@Name,@ClassId)";
  
            da.InsertCommand = new SqlCommand(sql,DBHelper.conn);
            SqlParameter sp=new SqlParameter();
                //Command 的参数配置,目的就是配置参数(@ClassName)的类型,版本应该是dataset的版本
            sp = da.InsertCommand.Parameters.Add("@ClassName", SqlDbType.NVarChar, 50);
            sp.SourceColumn = "ClassName";
            sp.SourceVersion = DataRowVersion.Current;

            sp = da.InsertCommand.Parameters.Add("@Name", SqlDbType.NVarChar, 50);
            sp.SourceColumn = "Name";
            sp.SourceVersion = DataRowVersion.Current;
            da.Update(ds,"Student");
            MessageBox.Show("插入数据成功!");
        }
    2.小小改进:(比较好的方式,我喜欢用的方式)
        private void btnAdd_Click(object sender, EventArgs e)
        {
            string sql = "Declare @ClassId int Select @ClassId = Id from Class where Name=@ClassName"
                          +" insert Student values(@Name,@ClassId)";
      //改动地点1:实例化的command对象用参数接受,这样就不用多次出现耦合度高的da.InsertCommand
     SqlCommand cmd = new SqlCommand(sql,DBHelper.conn);

            SqlParameter sp=new SqlParameter();
            sp = cmd.Parameters.Add("@ClassName", SqlDbType.NVarChar, 50);
            sp.SourceColumn = "ClassName";
            sp.SourceVersion = DataRowVersion.Current;

            sp = cmd.Parameters.Add("@Name", SqlDbType.NVarChar, 50);
            sp.SourceColumn = "Name";
            sp.SourceVersion = DataRowVersion.Current;

            da.InsertCommand = cmd;
            da.Update(ds,"Student");
            MessageBox.Show("插入数据成功!");
        }
     3.容易理解的方式:(容易理解的方式,不过要实例化多个SqlParameter,而上面实例化一次Command就OK,呵呵)
        private void btnAdd_Click(object sender, EventArgs e)
        {
            string sql = "Declare @ClassId int Select @ClassId = Id from Class where Name=@ClassName"+
                " insert Student values(@Name,@ClassId)";
            SqlCommand cmd = new SqlCommand(sql,DBHelper.conn);
  //配置参数
            SqlParameter sp=new SqlParameter();
            sp.ParameterName = "@Name";//设置参数的名称
            sp.SqlDbType = SqlDbType.NVarChar;
            sp.Size = 50;
            sp.SourceColumn = "Name";
            sp.SourceVersion = DataRowVersion.Current;
            cmd.Parameters.Add(sp);

            SqlParameter sp1 = new SqlParameter();
            sp1.ParameterName = "@ClassName";
            sp1.SqlDbType = SqlDbType.NVarChar;
            sp1.Size = 50;
            sp1.SourceColumn = "ClassName";
            sp1.SourceVersion = DataRowVersion.Current;
            cmd.Parameters.Add(sp1);
            da.InsertCommand = cmd;
            da.Update(ds,"Student");
            MessageBox.Show("插入数据成功!");
        }
    4.惊讶的发现:da可以同时配da.InsertCommand = cmd;da.UpdateCommand = cmd1;
        private void btnUpdate_Click(object sender, EventArgs e)
        {
            //更新数据用的sql语句
            string sql = "update Student set Name=@Name,ClassId=(select Id from Class where                                                Name=@ClassName) where Id=@Id";

  //配更新用的Command
            SqlCommand cmd = new SqlCommand(sql, DBHelper.conn);

            SqlParameter sp = new SqlParameter();
            sp = cmd.Parameters.Add("@ClassName", SqlDbType.NVarChar, 50);
            sp.SourceColumn = "ClassName";
            sp.SourceVersion = DataRowVersion.Current;

            sp = cmd.Parameters.Add("@Name", SqlDbType.NVarChar, 50);
            sp.SourceColumn = "Name";
            sp.SourceVersion = DataRowVersion.Current;

            sp = cmd.Parameters.Add("@Id", SqlDbType.Int);
            sp.SourceColumn = "Id";
            sp.SourceVersion = DataRowVersion.Original;
  //把配好的cmd赋给da.UpdateCommand
            da.UpdateCommand= cmd;

              //插入数据用的sql语句
            string sql1 = "Declare @ClassId int Select @ClassId = Id from Class where Name=@ClassName"                           +" insert Student values(@Name,@ClassId)";
                   //配查询用的Command
            SqlCommand cmd1 = new SqlCommand(sql1, DBHelper.conn);
            SqlParameter sp1 = new SqlParameter();
            sp1 = cmd1.Parameters.Add("@ClassName", SqlDbType.NVarChar, 50);
            sp1.SourceColumn = "ClassName";
            sp1.SourceVersion = DataRowVersion.Current;

            sp1 = cmd1.Parameters.Add("@Name", SqlDbType.NVarChar, 50);
            sp1.SourceColumn = "Name";
            sp1.SourceVersion = DataRowVersion.Current;

            sp1 = cmd1.Parameters.Add("@Id", SqlDbType.Int);
            sp1.SourceColumn = "Id";
            sp1.SourceVersion = DataRowVersion.Original;

              //把配好的cmd赋给da.UpdateCommand
            da.InsertCommand = cmd1;

  //把ds数据更新到数据库
            da.Update(ds, "Student");
            MessageBox.Show("写入数据成功!");
        }
    4.1 由上面的类,可以猜测SqlCommandBuilder的原理
        1.自动写sql语句,自动配置好参数(参数由表的所有字段组成,其中主键的版本是DataRowVersion.Original)
        2.实例化SqlCommand,并将参数增加到cmd.Parameters
        3.分别给da.InsertCommand和da.UpdateCommand赋值
        4.我曾试图只实例化一个SqlCommand,并把他赋给da的Command,但是没有成功,
               因为即使改一下da.InsertCommand.CommandText也改变了Command,
               而在更新前SqlParameterCollection又要唯一
         
  DgvUpdate_1Form(类似GirdView,外键列用ComboBox绑定表,可以用到SqlCommandBuilder) 
======================================

    1.查询显示(核心是仿GridView,用ComboBox来显示外键列)
       1.直接查询单表所有数据放入DataSet里(比如Student表的Id,Name,ClassId(外键))
       2.DataSet里的表和DataGridView绑定,
          并设置dgvStu_Class.Columns["Id"].DisplayIndex = 0;
                dgvStu_Class.Columns["Id"].HeaderText = "学生编号";....
                dgvStu_Class.Columns["ClassId"].Visible = false;
       3.新增DataGridViewComboBoxColumn dgvCbo
            ComboBox绑定Class表,dgvCbo加到dgv,设置dgvCol.DataPropertyName = "ClassId";
    1.1 条件查询(用DataTable的DefaultView)
         1.令人兴奋的是,再次查询所有数据时自动过滤(如:界面停到ClassTwo,修改数据后刷新,过滤依然有效))
           dt=ds.Tables["Student"];  Conditional=string.Format("Name like'%{0}%'",txtName.Text))
        public void FilterDgvStu_ClassByCondition(DataTable dt,string condition)
        {
            dt.DefaultView.RowFilter = condition;
        }
    2.修改和插入:(支持多行操作,而且修改和插入可以同时更新到数据库)
      1.由于用DataGridViewComboBoxColumn显示外键,增删改,就可以用sqlCommandBuilder了
          //将DataSet里数据更新到数据库
        public void UpdateDgvStu_Class(SqlDataAdapter da,DataTable dt)
        {
             //注意:new SqlCommandBuilder(da);这里面的da必须是填充数据到ds.Table["Student"]的那个da
             SqlCommandBuilder cmdb = new SqlCommandBuilder(da);
             da.Update(dt);
        }
        //更新按钮,修改和插入数据做好了,点此按钮直接更新到数据库
        private void btnUpdate_Click(object sender, EventArgs e)
        {
            //将数据更新到数据库的方法
            UpdateDgvStu_Class(da,ds.Tables["Student"]);
        }
     3.删除(支持多行,可以控制更新的范围,如:ds.Tables["Student"].GetChanges(DataRowState.Deleted))
 //由于删除是用快捷菜单,右键操作的,所以就直接更新到数据库了
        private void tsmiCancel_Click(object sender, EventArgs e)
        {
            //循环遍历被选中的行,然后从DataGridView里删除
            //由于DataGridView和DataSet里的表绑定,所以,DataGridView里删除就代表DataSet里删除了
            foreach (DataGridViewRow row in dgvStu_Class.SelectedRows)
            {
                dgvStu_Class.Rows.Remove(row);
            }
            //将DataSet里的数据更新的数据库,只更新被删除的部分)
            UpdateDgvStu_Class(da, ds.Tables["Student"].GetChanges(DataRowState.Deleted));
        }

 

你可能感兴趣的:(datagridview)