---------------------- 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培训、期待与您交流! ----------------------