学习交流,欢迎转载。转载请注明文章来源:http://www.cnblogs.com/lgjspace/archive/2011/10/12/2214007.html
小结:
SqlDataAdapter 相当于 DataSet 和数据库之间沟通的桥梁,无论是从数据库中取数据、把数据 Update 到数据库等,都需要用到 SqlDadaAdapter。
例如以下这段代码:
1 DataSet dataSet = new DataSet();
2 SqlDataAdapter adapter = new SqlDataAdapter(cmd);
3 adapter.Fill(dataSet);
4 .........
5 SqlCommandBuilder builder = new SqlCommandBuilder(adapter);
6 adapter.Update(dataSet);
细节:
C#中的可空类型(如:int? i = null;等)其实“真身”是泛型的结构体类型的 Nullable<T>,如下面两行功能效果是等价的:
1 int? i = null;
2 Nullable<int> i = null;
注意:
在使用强类型 DataSet 时相应的数据库一定要设定主键,否则会用不了强类型 DataSet。
技巧:
string.Format() 方法的应用例子:
1 string personMsg = string.Format("row.Id = {0}\nrow.Name = {1}\nrow.Age = {2}", row.Id, row.Name, row.Age);
2 MessageBox.Show(personMsg);
细节区别:
在强类型 DataSet 中,adapter 的 Fill() 和 GetData() 都是从数据库中提取数据,但两者之间存在区别:
调用 Fill() 方法时,强类型的 DataTable 对象要以参数的形式传进方法,来让 adapter 给自身“填充”数据,此种方式要求在调用 Fill() 之前必须已经存在一个待填充的强类型 DataTable;而调用 GetData() 时,提取出来的数据是以返回值的形式赋值给一个强类型 DataTable 的,不需要传进参数,这种方式不要求在调用前就创建好待填充的强类型 DataTable ,只要在调用 GetData() 函数后有一个强类型 DataTable 的变量来接载数据即可。
细节:
强类型 DataSet 命名潜规则:
表名+TableAdapter;
表名+DataTable;
表名+Row;
技巧:
在 VisualStudio 开发环境中,若名字下面出现有短横线出现,表示 VS 监测到有可添加的命名空间(namespace),可以用“解析”(或者 Ctrl + .)来自动地把引用命名空间的代码补全。
区别:
从强类型的 DataTable 实例(暂命名为:table)中获取第 0 个 Row,格式是:table[0],而不是像在弱类型中的那种table.Rows[0],要是这样的话强类型又会变回弱类型。
重点:
在使用强类型 DataSet 时一定要为表设定主键,如果不设主键,DataSet 的 TableAdapter 就不能够为 DataSet 自动地完成相关的 Command 。
注意:
在 VisualStudio 开发环境中,把一个表“拽”到强类型 DataSet 中的操作所代表的是:命令强类型 DataSet 按照“拖拽”进来的表的结构来设定好 DataSet 的结构和相关的设置,而不是把表里的数据一同“拖”到强类型 DataSet 中。“拖拽”动作之后,如果被拖拽的表发生了任何变化,该对应的强类型 DataSet 都不会被同步,若要把表的变化同步到强类型 DataSet 中,有两种办法:
1.删除掉原来的强类型 DataSet,然后再把表重新“拖拽”到数据集中,但如果你在 DataSet 中添加了一些Sql语句或者调用方法的话,这种方法会把这些变化都冲掉,因此不推荐。
2.右键单击强类型 DataSet (即拖拽后在页面中显示的“表”的以拖拽过来的表的表名命名的“表头”),选择“配置”,如果没有新增任何字段等的话,直接点击完成,即可完成同步更新;如果新增了字段,则点击右下角的“查询生成器”,然后在查询生成器上面显示的一个以被拖拽的表命名的“方框”中选择要添加的列(在要添加的列前面打钩),然后点确定,再点完成,即可完成同步。
重点注意:
在使用强类型 DataSet 时,当用其所属的 adapter 执行非查询语句(即非 Select 语句)后,改变的只是数据库里的数据,DataSet(即内存)里的数据是没有受到任何影响的,若要把改变同步到DataSet(内存)中,必需要重新执行 adapter 的 GetData() 或 Fill() 方法,这样才能从数据库中提取出最新的(被修改后的)数据回来。
重点细节:
1.强类型 DataSet 对应的 “表名+TableAdapter”类的对象(暂命名为 adapter )的 Connection 属性下的 State 属性可以获取或设置该 adapter 此时的链接状态。
2.强类型 DataSet 对应的 “表名+TableAdapter”类的对象(暂命名为 adapter )所执行的所有读和取数据的函数方法中都含有以下代码:
1 global::System.Data.ConnectionState previousConnectionState = this.Adapter.DeleteCommand.Connection.State;
2 if (((this.Adapter.DeleteCommand.Connection.State & global::System.Data.ConnectionState.Open)
3 != global::System.Data.ConnectionState.Open)) {
4 this.Adapter.DeleteCommand.Connection.Open();
5 }
6 try {
7 int returnValue = this.Adapter.DeleteCommand.ExecuteNonQuery();
8 return returnValue;
9 }
10 finally {
11 if ((previousConnectionState == global::System.Data.ConnectionState.Closed)) {
12 this.Adapter.DeleteCommand.Connection.Close();
13 }
14 }
从这段代码中可以大致看出一个链接的开关控制逻辑:
如果在打开连接动作前的连接状态不为 Open ,程序才会打开连接;
如果在关闭连接动作前的连接状态为 Close ,程序才会关闭连接。
利用上面这两点,我们可以最大限度地优化数据库的链接和读取性能:当调用 adapter 里的读取或操作数据库的函数方法前先把 adapter 的连接状态打开(即在调用函数前先执行“adapter.Connection.Open()”这行代码,让连接在方法调用前就被手动打开),然后在执行完该 adapter 的操作数据库的函数之后再把 adapter 的连接关闭(即在调用完函数之后执行“adapter.Connection.Close()”这行代码,让连接在方法调用之后被手动关闭),这种方法如果在大批量数据导入、导出处理的情况下使用,性能提升会非常非常明显!!!
注意!该优化方法只在 VS2008 (即 .NET 3.5)环境下测试过证实有效,在 VS2010(即 .NET 4.0)环境下测试没有任何明显的效果,估计是 .NET 4.0 已经对这部分代码进行了修改,但这只是个人猜测,有待证实。
重点、关键:
DataGridView 数据绑定步骤:
打开窗体,显示出工具箱,在工具箱顶端有一栏以“项目名+组件”命名的栏目(若没有,检查一下项目中有没有创建好强类型 DataSet 文件,如果确认已经创建 xsd(DataSet)文件,则把项目重新生成一遍,估计这样应该已经可以确定能看到。),选中该栏目里以 DataSet 的名称命名的强类型 DataSet 控件,以“表的名称+TableAdapter”命名的强类型的 adapter 控件,在“数据”栏里面拖出 BindingSource 和 DataGridView(该控件属可视控件,不同于前面的三个) 控件,这样,拖控件的步骤基本就完成了。然后到了设置的步骤,选中 BindingSource 控件,选择 DataSource 属性,在里面依次选择“其他数据源”→“From数据绑定列表实例”(切记!不是项目数据源!!)→“强类型DataSet的名称”,然后选择 DataMember 属性,在里面选择你想和 DataGridView 绑定的数据表(这是因为,强类型 DataSet 不仅仅可以包含一个table,还可以包含多个table,所以这里是指明 BindingSource 控件要绑定到 DataSet 中的哪个 table。);然后选中 DataGridView 控件,选择 DataSource 属性,在里面选择 BindingSource 控件的名字。这一大轮的“选择属性”的目的大体是:把 DataGridView 绑定到 BindingSource,把 BindingSource 绑定到 DataSet,DataSet 负责向数据库获取数据,而获取数据的动作则通过 Adapter 来完成。
技巧:
在一个 WinForm 项目中,假如有两个 WinFom 窗体 f1 和 f2,默认时是启动 f1。如果想把默认启动的窗体改成是 f2 的话,只需在项目中的 Program.cs 文件中找到“Application.Run(new Form1());”这行,把里面的 “From1”改成你想要默认启动的窗体名称即可实现效果。
细节:
在 DataGridView 控件中右键单击,选中“编辑列”,在打开的窗口中可以添加、删除在控件上被显示的列,也可以通过修改 HeaderText 属性的值来修改被显示的列的列名。其中通过修改 ToopTipText 属性的值还可以为该列的列名设置 ToopTips 信息(即当鼠标指针停靠到该列列名上时,指针旁边自动出现一个小小的提示框的效果,该 ToopTipText 属性就是设置提示框中显示的内容)。
细节:
当用强类型 DataSet 绑定了 DataGridView 之后,如果需要把在 DataGridView 上被修改的数据通过 Adapter 来 Update() 到数据库中的话,在 Update() 之前最好加上下面这两句,好让 Update() 之前先停止 DataGridView 的编辑状态:
1 dataGridView1.EndEdit();
2 dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
细节:
在已经和强类型 DataSet 绑定好了的 DataGridView 中,如果已经选中某个行(是“行”而不是“项”),执行 BindingSource.RemoveCurrent() 后该选中行(如果选中的是“项”,也按照选中了该选中“项”所在的“行”的情况来处理)会被从 DataSet 中(注意是 DataSet 中 而不是数据库中)删除。
细节:
在 DataGridView 中删除多行(但不会在数据库中也同时被删除掉)的参考代码:
1 if (dataGridView1.SelectedRows.Count <= 1) //判断当前在 DataGridView 中的选中项的个数。
2 {
3 bindingSource1.RemoveCurrent(); //如果只选中一个,直接删除。
4 }
5 else
6 {
7 foreach (DataGridViewRow row in dataGridView1.SelectedRows) //如果选中了多个项,遍历每个项。
8 {
9 dataGridView1.Rows.Remove(row); //删除每一个被选中的项(但不会在数据库中也同时被删除)。
10 }
11 }
技巧:
只要自己写的类直接或间接地继承自 Component 类的话,在VS的工具箱中就能“出现”你所写的类的“控件”了。
技巧:
通过 WinForm 窗体的 FormClosing() 方法可以让窗体在被点击自身的退出按钮时 FormClosing() 方法自身被触发,而通过设置该方法内的 e.Cancel 属性的值为 true 即可取消用户原来的“关闭窗口”的操作,相反地,设置 e.Cancel 属性值为 false 即为不取消用户原来的“关闭窗口”的操作;而 FormClosed() 方法则是在用户关闭窗口后触发,时机有一点点差别。以上两个方法的 e 参数都有 e.CloseReason 属性,该属性的值为枚举 CloseReason 类型,可通过此属性向另一窗口传递信息。
经验总结:
如果一个窗体被先后两次调用自身的 “this.ShowDialog()” 方法,且在后一次调用(ShowDialog 方法)时前一次调用(ShowDialog 方法)所弹出的窗口还没被关闭掉的话,会出现“已进行模式显示的窗体不能显示为模式对话框。请在调用 showDialog 之前关闭该窗体。”的报错信息,因此,如果需要多次弹出模态对话框,必须在后一次弹出模态窗口之前必须先
关掉前一次弹出的模态窗口。