制作时间: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));
}