ADO.NET一些注意问题

SqlDataReader是连接相关的, SqlDataReader中的查询结果并不是放到程序中的,而是放在数据库服务器中,SqlDataReader只是相当于放了一个指针(游标),只能读取当前游标指向的行,一旦连接断开就不能再读取。这样做的好处就是无论查询结果有多少条,对程序占用的内存都几乎没有影响。

SqlDataReader对于小数据量的数据来说带来的只有麻烦,优点可以忽略不计。ADO.Net中提供了数据集的机制,将查询结果填充到本地内存中,这样连接断开、服务器断开都不影响数据的读取。

DataSet dataset = new DataSet(); SqlDataAdapter adapter = new SqlDataAdapter(cmd); adapter.Fill(dataset);

SqlDataAdapter是DataSet和数据库之间沟通的桥梁。数据集DataSet包含若干表DataTable,DataTable包含若干行DataRow。foreach (DataRow row in dataset.Tables[0].Rows) row["Name"]。


sqlconnection在程序中一直保持它open可以吗?对于数据库来说,连接是非常宝贵的资源,一定要用完了就close、dispose。



DataSet的更新


可以更新行row["Name"] = "yzk"、删除行datatable.Rows.Remove()、新增行datatable. NewRow()。这一切都是修改的内存中的DataSet,没有修改数据库。
可以调用SqlDataAdapter的Update方法将对DataSet的修改提交到数据库,Update方法有很多重载方法,可以提交整个DataSet、DataTable或者若干DataRow。但是需要为SqlDataAdapter提供DeleteCommand、UpdateCommand、InsertCommand它才知道如何将对DataSet的修改提交到数据库,由于这几个Command要求的格式非常苛刻,因此开发人员自己写非常困难,可以用SqlCommandBuilder自动生成这几个Command,用法很简单:new SqlCommandBuilder(adapter)。查看生成的Command(没有直接赋值给SqlDataAdapter ,看SqlCommandBuilder的)。SqlCommandBuilder要求表必须有主键。
(*)通过DataRow的RowState可以获得行的状态(删除、修改、新增等);调用DataSet的GetChanges()方法得到变化的结果集,降低传递的资源占用。


C#中值类型(int、Guid、bool等)是不可以为空的,int i=null是错误的,因此int、bool等这些类型不能表示数据库中的“Null” 。因此C#提供了“可空类型”这种语法,只要在类型后加?就构成了可空的数据类型,比如int?、bool?,这样int? i=null 就可以了。解决数据库中int可以为null,而C#中int不能为null的问题。
判断可空类型是否为空,i==null或者i.HasValue;得到可空变量的值,int i1=(int)i.Value或者int i1=i.Value。
类型转换:不可空类型赋值给可空类型无需显式转换(一定成功),可空类型赋值给不可空类型则需显式转换(不一定成功)。


弱类型DataSet的缺点


只能通过列名引用,dataset.Tables[0].Rows[0][“Age”],如果写错了列名编译时不会发现错误,因此开发时必须要记着列名。
int age = Convert.ToInt32(dataset.Rows[0][“Age”]),取到的字段的值是object类型,必须小心翼翼的进行类型转换,不仅麻烦,而且容易出错。
将DataSet传递给其他使用者,使用者很难识别出有哪些列可以供使用
运行时才能知道所有列名,数据绑定麻烦,无法使用Winform、ASP.Net的快速开发功能。
自己动手写强类型DataSet(类型化DataSet,TypedDataSet),创建继承自DataSet的PersonDataSet类,封装出int? Age等属性和bool IsAgeNull等方法,向PersonDataSet中填充。



VS自动生成强类型DataSet


添加→新建项→数据集
将表从服务器资源管理器拖放到DataSet中。注意拖放过程是自动根据表结构生成强类型DataSet等类,没有把数据也拖过来,程序还是连的那个数据库,自动将数据库连接字符串写在了App.Config中。
代码中使用DataSet示例:CC_RecordTableAdapter adapter = new CC_RecordTableAdapter(); 如何得知Adapter的类名?选中DataSet中下半部分的Adapter,Name属性就是类名。需要右键点击类名→解析
取得所有的数据:adapter.GetData(),例子程序:遍历显示所有数据,i<adapter.GetData().Count;adapter.GetData()[i].Age。
常见问题:类名敲不对,表名+TableAdapter,表名+DataTable,表名+Row,然后用“解析”来填充类名,别照着我的代码敲。
常见问题:类的内部定义的类要通过包含namespace的全名来引用,不能省略。类的内部定义的类就能避免同一个namespace下类不能重名的问题。
强类型DataSet其实就是一种代码生成器的实现机制(DataSetPersons.Designer.cs),调用的***TableAdapter等类都是VS自动生成的,可以看到的,不要手动改生成的类代码,改xsd即可。
GetData和Fill的区别。



强类型强在哪?


像使用类的属性一样使用列名,dsPerson[0].Age,可以使用VS的自动提示功能,绝对不会写错列名,写错了编译通不过。
将强类型DataSet传递给其他人,使用者可以轻松确定有哪些列
int age = dsPerson[0].Age,列名的类型是明确的,避免类型转换的麻烦。
编译时就可以确定
名词:强类型DataSet(类型化DataSet),英文:Typed DataSet。
DataSet包含DataTable、DataTable包含DataRow,强类型DataSet同样如此。查看源代码看看VS帮我们做了什么
GetData返回是什么类型?每一行是什么类型?看类型定义即可得知。一般规律:表类型名:表名+DataTable,行类型名:表名+row,忘了也没关系:“转到定义”。


更新DataSet


调用Adapter的Update方法就可以将DataSet的改变保存到数据库。adapter.Update(datatable)
要调用Update方法更新必须设置数据库主键,后面的Delete也是如此。
常见错误:“当传递具有已修改行的 DataRow 集合时,更新要求有效的 UpdateCommand”,要为表设置主键。“谁都变了,唯有主键不会变”,程序要通过主键来定位要更新的行。忘了设主键怎么办?先到数据库中设置主键,然后在DataSet的对应DataTable上点右键,选择“配置”,在对话框中点击【完成】。好习惯:所有表都要设置主键!!!看看为什么会自动帮我们GetData、Update、Delete。


其他问题


插入新行,调用Insert方法。
增加字段怎么办?DataSet设计器中点【配置】,对话框中点【查询生成器】,勾选新增加的字段即可。删除字段同样如此。如果是高手也可以直接手改SQL语句。
要修改字段就要重新配置生成,这就是强类型DataSet的弱点,因此强类型DataSet不一定真的就是“强”,还是叫“类型化DataSet”(Typed DataSet)吧
常见错误:报错:数据为空。判断列的值为空的方法:Is**Null
为什么Select方法会填充、Update方法会更新,Insert方法会插入?没有多么神奇,看看Adapter的SelectCommand等属性,是那些SQL语句在起作用,如果有需要完全可以手工调整。



数据绑定


DataGridView绑定。拖放TableAdapter、DataSet、bindingSource,将bindingSource的DataSource设定为DataSet,设定DataMember属性,然后DataGridView绑定到bindingSource。在Load的时候调用TableAdapter的Fill方法将数据填充到DataSet。绑定:双方能同步感知对方的变化。
DataGridView绑定到BindingSource, BindingSource绑定到DataSet,所以DataGridView显示的是DataSet中的数据。
修改列标题。
将保存提交到数据库,在DataGridView中修改会同步反应到DataSet中,这样只要将DataSet Update到数据库就是“保存修改”,Update,保存前要dataGridView1.EndEdit(); dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);bindingsource1.EndEdit()已提交正在编辑的修改。
删除当前选择行:cCRecordBindingSource.RemoveCurrent(),只是删除DataSet中的数据,需要Update才能提交到数据库。
绑定单独控件,在控件属性的DataBindings中将属性绑定到BindingSource 的指定字段,这样控件中的值就会显示这个字段的值了
不会讲太多WinForm特有的东西。


探究(常考)


BindingSource是做什么的?维持当前项。这就是为什么详细控件和DataGridView会联动。试试控件绑定到不同的BindingSource。
Adapter的作用是负责DataSet和数据库之间的数据传递。
绑定到ComboBox。给Person增加一个TypeId字段(表示是黄种人、白种人、黑种人还是其他人种)。ComboBox的绑定分为显示数据项的绑定、选中值的绑定两个,DataSource属性设定要数据项绑定的数据源,DisplayMember属性为显示的属性、ValueMember为值(通过SelectedValue取得)的属性;然后绑定SelectedValue属性到表的字段。
DataGridView中的ComboBox列:设定列的ColumnType为DataGridViewComboBoxColumn为,然后其他绑定和普通ComboBox一样,由于BindingSource是维持当前项,所以记住“专BindingSource专用”


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值