黑马程序员_ADO.NET学习知识总结

来源:互联网 发布:英雄无敌2 mac 编辑:程序博客网 时间:2024/05/07 12:25

---------------------- Windows Phone 7手机开发、.Net培训、期待与您交流! ----------------------


ADO.NET  我现在单单的理解为用来对数据库进行操作的一种机制


数据库的连接


建立数据库连接需要引用System.Data.SqlClient;指令


ADO.Net通过SqlConnection类创建到SQL Server的链接,

执行非查询T-SQL语句

SqlCommand        ExecuteScalar()方法   用于返回第一行、第一列的数据

SqlDataReader     ExecuteReader 执行有多行结果集

ExecuteScalar()方法   用于返回第一行、第一列的数据


连接中所用到的SqlDataReader ,SqlCommand等实例都继承了IDispose接口

对于数据库来说,连接是非常宝贵的资源,所以用完了一定要close,dispose

用using是因为在执行完语句之后它会自动关闭(自动调用Dispose)

Close() 关闭后还能打开       Dispose() 直接撤销,不能再打开
SqlConnection、FileStream等的Dispose内部都会做这样的判断:判断有没有close,如果没有close就先close再Dispose


SqlConnection数据库连接代码:

一种,用户实例登陆(非视频中老师用的数据库连接字符串),不需要项目内嵌mdf文件

在VS里边用Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Database1.mdf;Integrated Security=True;User Instance=True

如果用添加用户实例登陆会验证失败,VS好像不支持自带SQL Server用户登陆(这只是我觉得,因为就登陆这弄了两天,怎样都不成功,用windows身份验证就OK)

不过这种连接数据库字符串貌似不能被配置文件识别,所以,还是乖乖的按老师教的用。

    public class MyDataBaseService    {        /// <summary>        /// 获取数据库连接        /// </summary>        /// <returns></returns>        private static SqlConnection GetConn()        {            SqlConnection conn = new SqlConnection();  //创建数据库连接            string connStr = "server=sky-dong-pc;uid=sa;pwd=sa;database=PersonBank";           //server=sky-dong-pc为连接数据库所用的计算机名   uid为账号  pwd为密码 database为所要连接的数据库            conn.ConnectionString = connStr;            conn.Open();  //打开数据库            return conn;        }     }



另一种,windows身份验证(老师所讲的),项目内嵌mdf文件形式,会有些麻烦,而且好些代码不知道是干什么

在连接数据库之前需要将这段代码在WinFrom程序中放在main函数中(如果不加这段代码,更改数据库数据 它改的是Debug文件下得数据库,而不是所操作的数据库)

string dataDir = AppDomain.CurrentDomain.BaseDirectory;        if (dataDir.EndsWith(@"bin\Debug\") || dataDir.EndsWith(@"bin\Release"))           {              dataDir = System.IO.Directory.GetParent(dataDir).Parent.Parent.FullName;                AppDomain.CurrentDomain.SetData("DataDirectory",dataDir);           }



然后将方法一中的

string connStr = "server=sky-dong-pc;uid=sa;pwd=sa;database=PersonBank";


改为

"Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Database1.mdf;Integrated Security=True;User Instance=True“

Database1.mdf问连接数据库文件,其他都一样

ADO.NET程序有两段非常重要的代码


SqlCommand SqlDataReader



            using (SqlConnection conn = new SqlConnection(connStr))  //创建数据库连接            {                conn.Open();                using (SqlCommand cmd = conn.CreateCommand())  //创建一个查询对象                {                    cmd.CommandText = "select * from promary";  //查询语句                    using (SqlDataReader read = cmd.ExecuteReader())  //返回多个结果集                    {                        while (read.Read())                        {                            ProvinceItem item = new ProvinceItem();  //定义的ProvinceItem 类,里边有Id和Name两个属性                            item.Id = read.GetInt32(read.GetOrdinal("proID"));                            //readerde GetString、GetInt32等方法只接受整数参数,也就是序号, 用GetOrdinal方法根据列名动态得到序号                            item.Name = read.GetString(read.GetOrdinal("proName"));                            cmbSheng.Items.Add(item);                        }                    }                }            }



Prarmeters,防止漏洞参数化查询

让用户输入用户名,密码时如果SQL语句写成

cmd.CommandText="select count(*) from T_Users where UserName='"+username+"'";, password='"+password+"'时输入密码就可能造成漏洞参数化 输入1‘or ’1‘ = ’1 也可以登陆成功

为了防止,则需要将用户输入的参数加到Prarmeters,然后由Prarmeters进行传值

Prarmeters用法:

   cmd.CommandText="select count(*) from T_Users where UserName=@UN and password=@P";

   cmd.parameters.Add(new SqlParameters("UN",username));
   cmd.parameters.Add(new SqlParameters("P",username));


using(SqlCommand cmd = conn.CreateCommand()){   cmd.CommandText="select count(*) from T_Users where UserName=@UN and password=@P";   //如果直接写成cmd.CommandText="select count(*) from T_Users where UserName='"+username+"', password='"+password+"'";   //输入密码就可能造成漏洞参数化 输入1‘or ’1‘ = ’1 也可以登陆成功   cmd.parameters.Add(new SqlParameters("UN",username));   cmd.parameters.Add(new SqlParameters("P",username));   int i=Convert.ToInt32(cmd.ExecuteScalar());   if(i>0)   {Console.WriteLine("登陆成功!");   }   else   {Console.WriteLine("登陆失败!");}



Prarmeters类型转换的一个BUG

它传参数0的时候它就会自动默认为调用 类型的一个重载,要想给里边传常量,就得将其转换为object类型

cmd.parameters.Add(new SqlParameters("UN",(object)0)); 

数据库的查询、更新

可以将此代码跟数据库连接方法一的代码放在一个类文件中,方便调用,修改,当然,需要重复写的代码都可以放在单独一个文件中方便调用



        /// <summary>        /// 执行修改sql语句,如insert\update\delete        /// </summary>        /// <param name="sql"></param>        /// <returns></returns>        public static int ExecuteModi(string sql)        {            using (SqlConnection conn = GetConn())            {                SqlCommand cmd = new SqlCommand();//创建执行命令的对象                cmd.Connection = conn;//指定数据库连接                cmd.CommandText = sql;//指定要执行的sql语句                try                {                    return cmd.ExecuteNonQuery();//执行, 并返回受影响的行数                }                catch                {                    return -2;                }            }        }



配置文件


如果一个程序中多处会用到数据库连接字符串,则可以将连接数据库字符串写在一个应用程序配置文件中,方便修改

方法:在项目中添加一个应用程序配置文件

然后给里边添加
<connectionStrings>
<add name="自己取个名字" connectionString="连接字符串">
</connectionStrings>


要用到这个配置文件,则需要在项目引用里边添加System.Configuration ,然后再项目中引用using System.Configuration指令就可以用了

引用方法:

ConfigurationManager.ConnectionStrings["配置文件中自己取的名字"].ConnectionString        得到字符串



DataSet数据集(返回DataTable类型的查询数据的集合)

DataSet非为弱类型DataSet和强类型DataSet

DataSet和DataReader的区别


DataReader是直接从数据库取数据的,所以,出了using范围它就停止了(占用内存可以忽略不计)
而DataSet是从数据库中查出数据,饭后返回一个数据集,即使除了using范围,照样可以调用(缺点:查询结果占用内存,要查询数据量过大时它会把内存撑爆,所以,还是要用DataReader,DataSet只是在查询数据量小得时候使用)


DataSet用法代码


        public static DataTable OpenQuery(string sql)        {             using (SqlConnection conn = GetConn())            {                SqlDataAdapter sda = new SqlDataAdapter(sql, conn);                DataSet ds = new DataSet();                sda.Fill(ds);                return ds.Tables[0];            }        }


调用:


 DataTable dt = OpenQuery(" select * from table");  //DataSet返回值为DataTable类型的,所以,需要定义一个DataTable类型的变量来接受返回值 for(int i=0;i<dt.Rows.Count;i++) {    DataRow row = dt.Rows[i];//返回每一行    string name=Convert.ToString(row["列名"]);    MessageBox.Show(...); }


DataSet的更新

但是,DataSet是进行离线查询的,修改的数据只存在在内存中,要想修改到数据库中,就需要用到sda.Update(ds)方法更新数据(这只是修改到内存中),

然后需要创建新的Command,然后CommandText用更新语句将数据修改到数据库

或者使用SqlCommandBuilder   系统会自动为我们添加更新语句


        public static DataTable OpenQuery(string sql)        {             using (SqlConnection conn = GetConn())            {                SqlDataAdapter sda = new SqlDataAdapter(sql, conn);                DataSet ds = new DataSet();                sda.Fill(ds);//DataSet更新数据                DataTable dt = ds.Tables[0];DataRow row = dt.Rows[0];row["Name"]="张三";table.Rows.RemoveAt(1);  //移除制定行table.NewRow();   //新建行sda.InsertCommand = conn.CreateCommand();sda.InsertCommand.CommandText="insert into..."  //自己写Command,比较麻烦//使用SqlCommandBuilder   系统会自动为我们添加更新语句SqlCommandBuilder builder = new  SqlCommandBuilder(sda);  //也可以直接new,不用实例new SqlCommandBuilder(sda);  sda.Update(ds);            }        }



可空数据类型

如果数据库中有一个int 类型的字段可以为空类型,但是C#的int类型不能为空类型,所以,就需要声明一个可空类型的int

声明方法: 在int后加?

int? i=0;
int? j=null;


弱类型DataSet的缺点

只能通过列名引用,dataset.Tables[0].Rows[0]["Age"],如果写错了列名编译时不会发生错误,因此开发者必须要记着列名
int age=Convert.ToInt32(dataset.Rows[0]["Age"]),取到的字段的值都是object类型,必须小心翼翼的进行转换,不仅麻烦,而且容易出错
将Dataset传递给其他使用者,使用者很难识别出有哪些列可以供使用
运行时才知道所有的列名,数据绑定麻烦,无法使用winform,asp.net的快速开发功能

强类型DataSet(其实就是一种代码生成机制)


强类型使用的两种方法,一种是自己写,一种是利用系统自动为我们生成


自己写:

新建一个类,该类继承自DataRow,里边建立对应数据库各个字段的属性


        public int proID        {            get            {                return Convert.ToInt32(this["proID"]);            }            set            {                this["proID"] = value;            }        }        public string proName        {            get            {                return Convert.ToString(this["proName"]);            }            set            {                this["proName"] = value;            }



另一种方法:调用VS自带函数

新建一个数据集文件  将需要创建的表拖到数据集设计图界面(数据集只是根据字段名生成一个强类型的DataSet,并没有将数据拖过来)
然后将文件名.数据集名引用进来
using 文件名.数据集名
然后添加代码:


            //promaryTableAdapter为数据集名称            promaryTableAdapter adapter = new promaryTableAdapter();            //获得数据需要将数据集的全称引入,因为它们不再同一命名空间下            AdoCity.DataSet1.promaryDataTable data = adapter.GetData();            for (int i = 0; i < data.Count; i++)            {  //得到返回数据的某一行                AdoCity.DataSet1.promaryRow userRow = data[i];                MessageBox.Show(userRow.proID.ToString());            }



类型化DataSet的更新

调用adapter的Update(data)方法更新数据,使用强类型DataSet的时候一定要设置主键,系统会自动加上更新语句
如果没有主键,则无法修改
修改表之后要想在数据集里边更新 需要右键->配置->然后完成,配置文件就会更新

增加字段  右键->配置->查询生成器,然后勾选需要增加的字段。  删除也是一样      也可以自己写SQL语句

这也是强类型DataSet的弱点


如果字段名里边有NULL则需要判断字段名是否为空  调用T_PersonsRow的IsNameNull方法
            if (p.IsNameNull())
            {
                MessageBox.Show("姓名为空");
            }
            else
            {
                MessageBox.Show(p.Name);
            }

强类型DataSet中增加自己的SQL语句

在数据集中 右键->添加->Query    写好之后为自己的方法取个名字

调用自己的SQL语句,跟GetData相同,直接adapter.自己的SQL方法名字


DataSet批量操作


在需要导入大量数据的时候就需要手动将连接打开,导入完之后再进行关闭

adapter.Connection.Open();
for(int i=1;i<=3000;i++)
{
   adapter.Insert(i.ToString(),i.ToString(),0);
}
adapter.Connection.Close();


就整理了这么多,可能里边有错误


---------------------- Windows Phone 7手机开发、.Net培训、期待与您交流! ----------------------

详细请查看:http://edu.csdn.net/heima/

原创粉丝点击