在这个系列的上一篇文章里,我写了一丁点有关服务器控件的使用笔记。
其实当菜鸟们用.net开发久了就会发现,微软提供的服务器控件几乎是没有人使用的,因为大家都想深度定制自己需要的控件,这样在性能和需求上都能够得到满足,说白了也就是自己写控件。
也有大牛对带有“控件”字眼的知识一律表示强烈的鄙视和不屑,他们提倡使用ASP.NET MVC,觉着这个才是王道。
我对.net了解只是皮毛,所以我说不出有关.net的“正确”的开发模式,呵呵,哥只是菜鸟。
转回正题,今天把自己使用ADO.NET的过程中积累的笔记分享给大家。
轻度科普:ADO.NET是用于在.NET中与数据库进行交互的一个模块,当你编写的.NET程序需要和数据库进行数据交换的时候,就需要用到ADO.NET。
ADO.NET的基本使用流程:
(1)建立指向数据库的连接。
(2)建立需要执行的SQL语句。
(3)打开连接执行SQL语句。
(4)关闭连接返回提示信息。
正文
一、使用ADO.NET技术所需命名空间
System.Data
System.Data.SqlClient
二、使用SqlConnection对象连接数据库时所需的连接字符串
身份验证模式:
@"Server=服务器名;Database=数据库名;User ID=数据库用户名;Password=数据库密码;"
信任模式:
@"Server=服务器名;database=数据库名;Trusted_Connection=True;"
三、拼接连接字符串的方法
(1)string.Format("Server={0};Database={1};User ID={2}....",Textbox1.Text....)
[非常不安全,不能防止SQL注入攻击]
解决方案:使用参数化SQL与存储过程提高安全性
对于不同的数据供应器都有对应的Parameter来表示SQL语句或者存储过程中的各种参数。参数和数据库字段的真实类型一一对应,所有参数的值会仅仅被认为是一个参数,因此,在参数中写任何SQL语句都是没有意义的。
eg:
SqlCommand cmd=new Sqlcommand("Select count(*) from tbClass where ClassName=@ClassName",conn) cmd.Parameters.Add("@ClassName",SqlDbType.VarChar,50) cmd.Parameters["@ClassName"].Value=tb_ClassName.Text;
SqlCommand cmd=new Sqlcommand("Select count(*) from tbClass where ClassName=@ClassName",conn) cmd.Parameters.Add("@ClassName",SqlDbType.VarChar,50) cmd.Parameters["@ClassName"].Value=tb_ClassName.Text;
注意:
SQL语句或者存储过程中指定的所有参数必须和Parameters属性中所有参数对应
另外还有一个AddWithValue()方法可以同时为参数赋值:
cmd.Parameters.AddWithValue("@ClassName",tb_ClassName.Text);
这句话可以代替上面的两句话了,它会自动检测参数的类型和长度。
SqlParameter对象有一个Direction方法,它用来指定存储过程参数的方向,它的值由ParameterDirection枚举来定义,共有4个:Input,InputOutput,Output,ReturnValue。
(2)使用ConnectionStringBuilder类。
eg:
SqlConnectionStringBuilder me=new SqlConnectionStringBuilder(); me.DataSource=XX.Text; me.InitialCatalog=XX.Text; me.UserID=XX.Text;
SqlConnectionStringBuilder me=new SqlConnectionStringBuilder(); me.DataSource=XX.Text; me.InitialCatalog=XX.Text; me.UserID=XX.Text;
SqlConnectionStringBuilder me=new SqlConnectionStringBuilder(); me.DataSource=XX.Text; me.InitialCatalog=XX.Text; me.UserID=XX.Text;
然后实例化SqlConnection时作为构造函数的参数传递进去:
SqlConnection conn=new SqlConnection(me.ConnectionString);
四、越晚打开SqlConnection越好,越早关闭SqlConnection越好
对于SqlConnection,我们可以使用using{}语句块来自动释放活动连接:
using (SqlConnection conn=new SqlConnection(sConnectionString)) { conn.Open(); using(SqlCommand cmd=new SqlCommand(sSql,conn)) { cmd.ExecuteNonQuery(); } }
使用了using以后,Connection对象不再需要Close(),using语句会在代码块结束的时候自动调用相应对象的Dispose()方法来释放对象资源,对于涉及到系统资源的对象,微软建议用using
五、使用Sqlcommand对象执行存储过程
简要例子如下:
//建立Command对象,输入存储过程名 SqlCommand cmd=new SqlCommand("存储过程名",conn); //修改Command对象的CommandType属性为执行存储过程,默认为CommandType.Text,用于执行SQL语句 cmd.CommandType=CommandType.StoredProcedure; //添加参数及赋值 cmd.Parameters.Add("@ClassName",SqlDbType.VarChar,50); cmd.Parameters["@ClassName"].Value=xx.Text; //指定参数方向 cmd.Parameters["@ClassName"].Direction=ParameterDirection.Input;
六、关于DataReader的说明
(1)DataReader对象不能直接使用new关键词实例化,可通过Command对象的ExecuteReader()方法获得一个DataReader对象
(2)DataReader是只读只进的读取方式,且是一行一行向前读取记录的,因此常使用while(DataReader.Read())来遍历所有行。
(3)在真正读取某行某列值以前应该使用DataReader的IsDBNull(列索引号)方法来判断某列是否有值,以免因为不能进行类型转换导致异常。
(4)读取多表时可以只用一个DataReader,方法是用DataReader的NextResult()方法
七、关于如何创建DataSet的简要例子
//建立数据库 DataSet Forum = new DataSet ("Forum"); //建立一张数据表 DataTable tbClass = new DataTable("tbClass"); //把数据表加入数据库 Forum.Tables.Add(tbClass); //建立tbClass的一列 DataColumn ClassID=new DataColumn("ClassID",typeof(System.String)); //设定ClassID列不允许空 ClassID.AllowDBNull=false; //把列加入tbClass表 tbClass.Columns.Add(ClassID); //设定tbClass表的主键 tbClass.PrimaryKey = new DataColumn[] { ClassID }; //添加行记录 for(int i=1;i<=5;i++) { //实例化tbClass表的行 DataRow tbClassRow = tbClass.NewRow(); //为行中每一列赋值 tbClassRow["ClassID"]=Guid.NewGuid(); //把行加入tbClass表 tbClass.Rows.Add(tbClassRow); }
注意:
DataTable不加入DataSet是没有实用意义的,它无法单独使用,同理,DataColumn要加入到DataTable
对于DataTable的primaryKey属性,它需要赋值一个DataColumn数组,因为主键可由几列共同组成。
DataRow是不能直接实例化的,因为数据行是属于数据表的,只能通过NewRow()方法获取一个行。
八、SqlDataAdapter & SqlConnection
对于SqlDataAdapter,无需打开Connection对象,也无需关闭。它会自己管理相关的连接。
九、HTML页面绑定数据写法
'<%# DataBinder.Eval(Container.DataItem,"你的数据变量") %>'
十、数据库连接时间设置
默认情况下连接数据库的超时时间是15秒,我们可以通过调整连接字符串的方法来改变只读的ConnectionTimeout属性。只需在初始化SqlConnection类的变量时加上一句: Connection Timeout= 2;即可将超时时间调为2秒。
十一、枚举所有可用数据源的方法
可以使用SqlDataSourceEnumerator类(System.Data.Sql命名空间)来实现枚举。例子如下:
注:ddl_Server为下拉列表框控件ID,另外,这个操作非常的慢,要谨慎使用。
SqlDataSourceEnumerator instance =SqlDataSourceEnumerator.Instance; ddl_Server.DataSource=instance.GetDataSources(); ddl_Server.DataTextField="ServerName"; ddl_Server.DataBind();
十二、使用DataAdapter填充DataSet
利用DataAdapter填充DataSet后,DataSet中的表的命名默认为Table、Table1、Table2,依此类推。可以用DataTableMapping类对DataTable和DataColumn进行一个友好名称的映射,在使用Fill方法前,用如下代码:
例子:
DataTableMapping dtmClass = adapter.TableMappings.Add("Table","新名字1"); dtmClass.ColumnMappings.Add("ClassID","新名字");
注意:DataTableMapping类属于System.Data.Common命名空间。
十三、SQL常用类型
uniqueidentifier 用于GUID主键列。把该列的数据类型设为这个,然后把默认值设置为(newid())来实现GUID。如果主键列是GUID,则不需要再对其赋值。
varchar/char 长度均在1~8000之间,它们的区别在于char是定长字符数据,而varchar是变长字符数据。所谓定长就是长度固定的,当输入的数据长度没有达到指定的长度时将自动以英文空格在其后面填充,使长度达到相应的长度;而变长字符数据则不会以空格填充。
int 4个字节
bit 1或0的整数数据。用于存储布尔类型的数据。
datetime 1753年1月1日~9999年12月31日之间的日期和时间数据,精确到30毫秒。
text text存储可变长度的非Unicode数据,最大长度为2的31次方-1个字符.