传智的ADO.NET

ADO.NET基础
程序要和数据库交互要通过ADO.NET进行,通过ADO.NET就能再程序中执行SQL了。ADO.ENT中提供了对各种不同的数据库的统一操作接口。
直接在项目中内嵌mdf文件的方式使用SQLSERVER数据库(基于服务的数据库).mdf跟项目走,用起来方便,和在数据库服务器上创建数据库没什么区别,运行的时候自动附加(Attach).
双击mdf文件会在“服务器资源管理器”中打开,管理方式和在Management Studio没有什么本质不同。要拷贝mdf文件需要关闭所有指向mdf文件的连接。
正式生产运行的时候附加到SQLSERVER上、修改连接字符串即口,除此之外没有任何的区别,在“数据库”节点上点右键“附加”;在数据库节点上==》任何==》分离就可以得到拷来拷去mdf文件。
用的时候要在控制台、Winform项目中在Main函数最开始的位置加入备注中的代码。ASP.NET项目不需要。

ExecuteScalar
SqlCommand的ExecuteScalar方法用于执行查询,并返回查询所返回的结果集中的第一行的第一列,因为不能确定返回值的类型,所以返回值是object类型。
cmd.CommandText="select count(*) from T+Users",int i = Convert.Toint32(cmd.ExecuteScalar())
cmd.CommandText = "select getdate()";
DateTime dt = Convert.ToDateTime(cmd.ExecuteScalar())
得到自动增长字段的主键值,在values关键字前加上outputinserted.Id,其中Id为主键字段名。执行结果就试插入的主键值,用
ExecuteScalar执行最方便。
   cmd.CommandText = "insert into T_Users(UserName,Password) output inserted.Id values('admin','888888')";
int i = Convert.ToInt32(cmd.ExecuteScalar());

执行查询
执行有多行结果集的用ExecuteReader
SqlDataReader reader = cmd.ExecureReader();
while(reader.Read())
{
  Console.WriteLine(reader.GetString(1));
}
reader的GetString GetInt32等方法只接受整数参数,也就是序号,
用GetOrdinal方法根据列名动态得到序号
练习:控制台登陆程序。
为什么用using.
Close:关闭以后还能打开。
Dispose:直接销毁,不能再次使用。
using在出了作用域以后调用Dispose,SqlConnection FileStream等的Dispose内部都会做这样的判断:判断有没有close,如果没有Close就先Close再Dispose.

连接SQLServer
连接字符串:程序要通过连接字符串指定要连哪台服务器上的 哪个实例的哪个数据库 用什么用户名密码等。
项目内嵌mdf文件形式的连接字符串"Data Source=./SQLEXPRESS;AttachDBFilename=|DataDirectory|/Database1.mdf;Integrated Security=True;User Instance=True".
"./SQLEXPRESS"表示“本机上的SQLEXPRESS实例”,如果数据库实例名不是SQLEXPRESS,则需要修改。
"Database1.mdf"为mdf的文件名
ADO.NET中通过SqlConnetion类创建到SQLServer的连接,SqlConnection代表一个数据库连接,ADO.NET中的连接资源都实现了IDisposable接口,可以使用using进行资源管理。执行备注中的代码如果成功了就OK。

将连接字符串写在代码中的缺点:多次重复,违反了DRY(Don't Repeat yourself)原则;如果要修改连接字符串就要修改代码。将连接字符串写在App.Config中。
1.添加App.config文件:添加==》新建项==》常规==》应用程序配置文件。App.config是.Net的通用配置文件,在ASP.Net中也能同样适用。
2.在App.config中添加connectionStrings段,添加一个add项,用name属性起义个名字(比如DbConnStr),connectionString属性指定连接字符串。
3.在“引用”节点上点右键“添加引用”,找System.configuration.不是所有的.Net中的类都能直接调用,类所在的Assembly要被添加到项目的引用中才可以。
4.ConfigurationManager.ConnectionStrings["DbConnStr"].ConnectionString得到连接字符串。
5.如何在部署的程序中修改配置。

DataSet
每次读取数据都会创建连接 执行Command得到SqlDataReader太麻烦,让我们封装一个方法吧!
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.Table[0].Rows) row["Name"].
SQLHelper
封装一个SQLHelper类方便使用,提供ExecuteDataTable(string sql,params SqlParameter[] parameters)
ExecuteNonQuery(string sql,params SqlParameter[] parameters) ExecuteScalar(string sql,params SqlParameter[] parameters)等方法。网上有微软提供的最全的SQLHelper类,是Enterprise Library中的一部分。
new SqlParameter("3",0)的陷阱
sqlconnection在程序中一直保持它的open可以吗?对于数据库赖说,连接时非常宝贵的资源,一定要用完了就close dispose.
DataSet
可以更新行row["Name"]="yzk" 删除行datatable.Row.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 i 1 = (int)i.Value.
类型转换:不可控类型赋值给可控类型无需显示转换(一定成功),可控类型赋值给不可控类型则需显示转换(不一定成功)。
弱类型DataSet
只能通过列名引用,dataset.Tables[0].Rows[0]["Age"],如果写错了列名编译时不会发现错误,因此开发时必须要记着列名。
int age = Convert.Toint32(dataset.Row[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
调用Adapter的Update方法就可以将DataSet的改变保存到数据库。adapter.Update(datatable)
要调用Update方法更新必须设置数据库主键,后面的Delete也是如此。
常见错误:“当传递具有已修改行的DataRow集合时,更新要求有效的UpdateCommand”,要为表设置主键。“谁都变了,唯有主键不会变”,程序要通过主键赖定位要更新的行。忘了设主键怎么办?先到数据库中设置主键,然后再DataSet的对应DataTable上点右键,选择“配置”,再对话框中点击【完成】。好习惯:所有表都要设置主键!!!看看为什么会自动帮我们GetData Update Delte.
其他问题
插入新行,调用Insert方法
增加字段怎么办?DataSet设计器中点【配置】,对话框中点【查看生成器】,勾选新增加的字段即口。删除字段同样如此。如果是高手也可以直接手动SQL语句。
要修改字段就要重新配置生成,这就是强类型DataSet的弱点,因此强类型DataSet不一定真的就是“强“,还是叫”类型化DataSet“吧
常见错误:报错:数据为空。判断列的值为空的方法:Is**Null
为什么Select方法会填充 Update方法会更新 Insert方法会插入?没有多么神奇,看看Adapter的SelectCommand等属性,是那些SQL语句在起作用,如果有需要完全可以手工调整。

类型化DataSet批量处理
创建TableAdapter对象后,首先将它打开,执行command操作后再关闭。这样至始至终就只创建了一个连接,连接是非常宝贵

的,尽量创建很少的连接,这样能提高效率,在进行批量处理的时候非常重要。这是从TableAdapter对象执行command的方法中看出来的==》如果以

前的连接时关闭的就打开,是关闭的就关闭,哈哈,这样就没必要每次执行一下command就创建一个连接。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值