一:DataSet和DataAdapter
DataSet完全独立于数据源,可以和数据源连接或完全断开。基本作用是为存储在内存缓存中的数据提供关系视图。
DataAdapter可以作为数据集和数据源之间的桥梁。没有它,数据集就不能访问任何类型的数据源。
1: 如果只想读取和显示数据,则只需要使用数据读取器即可。
如果需要处理数据并更新数据库,这是就需要用到数据集。
数据适配器可以使用数据读取器填充数据集。
2: 数据集
允许在本地高速缓存中存储和修改大量数据,把数据看做表,以脱机方式处理数据。
数据集就像一只水桶,可以装水,但需要外部管道把水引入。即需要数据适配器来填充数据,支持对数据源的访问。
数据集-->数据适配器-->数据源
二:DataSet和DataAdapter的使用
1: 数据集的构造
DataSet ds = new DataSet();//默认名为NewDataSet
DataSet ds = new DataSet("myds");
conn = new SqlConnection(@"
server=./sqlexpress; integrated security=true; database=northwind");
String sqlComTxt = @"select productname , unitprice from products where unitprice < 20";
conn.Open();
SqlDataAdapter da = new SqlDataAdapter(sqlComTxt, conn);
DataSet ds = new DataSet();
da.Fill(ds, "products");
DataTable dt = ds.Tables["products"];
foreach (DataRow row in dt.Rows)
{
foreach (DataColumn col in dt.Columns)
{
Console.WriteLine(row[col]);
}
}
2: 数据集的筛选和排序
没有显式打开连接,调Fill时,如果连接未打开,该方法会自动打开,填充完后,自动关闭连接。
如果是手动打开的,则该方法不会再打开连接了,而且也不会在之后自动关闭。
conn = new SqlConnection(@"
server=./sqlexpress; integrated security=true; database=northwind");
String sqlComTxt1 = @"select * from customers ";//后面接个空格很重要
String sqlComTxt2 = @"select * from products where unitprice < 10";
String sqlComTxt = sqlComTxt1 + sqlComTxt2;
SqlDataAdapter da = new SqlDataAdapter(sqlComTxt, conn);
da.SelectCommand = new SqlCommand(sqlComTxt, conn);
DataSet ds = new DataSet();
//每个查询返回一个结果集,每个结果集都存储在单独的DataTable对象中。
da.Fill(ds, "dstable");
DataTableCollection dtc = ds.Tables;
string filter1 = "country = 'Germany'";
string sort = "companyname asc";
//select * from customers where country = 'Germany' ORDER BY companyname ASC
foreach (DataRow row in dtc["dstable"].Select(filter1, sort))//dtc[0].Select(filter1, sort)
{
Console.WriteLine("{0}/t{1}", row["companyname"].ToString(), row["contactname"].ToString());
}
foreach (DataRow row in dtc["dstable1"].Rows)//dtc[1].Rows
{
Console.WriteLine("{0}/t{1}", row["productname"].ToString(), row["unitprice"].ToString());
}
3: 数据视图
数据视图也可以完成动态筛选和排序数据所包含的数据。
可以创建存储在底层数据表中的数据的动态视图,以反映对其内容和数据数据所作的变化。
conn = new SqlConnection(@"
server=./sqlexpress; integrated security=true; database=northwind");
String sqlComTxt = "select contactname, country from customers";
SqlDataAdapter da = new SqlDataAdapter(sqlComTxt, conn);
da.SelectCommand = new SqlCommand(sqlComTxt, conn);
DataSet ds = new DataSet();
da.Fill(ds, "dstable");
DataTable dt = ds.Tables["dstable"];
//表,筛选器SELECT,排序列ORDER BY。
DataView dv = new DataView(dt, "country='Germany'", "contactname", DataViewRowState.CurrentRows);
foreach (DataRowView drv in dv)
{
for (int index = 0; index < dv.Table.Columns.Count; index++)
{
Console.Write(drv[index] + "/t");
}
Console.WriteLine();
}
4: 修改数据集中的数据
对数据集所做的变化不会自动保存到数据库中。如果要保存的话,需要再次连接到数据库并显式的完成更新。参考第三部分。
conn = new SqlConnection(@"
server=./sqlexpress; integrated security=true; database=northwind");
String sqlComTxt = "select * from employees where country = 'UK'";
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = new SqlCommand(sqlComTxt, conn);
DataSet ds = new DataSet();
da.Fill(ds, "dstable");
DataTable dt = ds.Tables["dstable"];
dt.Columns["firstname"].AllowDBNull = true;
dt.Rows[0]["city"] = "wilmingtom";
DataRow dr = dt.NewRow();
dr["firstname"] = "Roy";
dr["lastname"] = "Beatty";
dr["titleofcourtesy"] = "Sir";
dr["city"] = "Birmingham";
dr["country"] = "UK";
dt.Rows.Add(dr);
foreach (DataRow row in dt.Rows)
{
Console.WriteLine("{0}/t{1}/t{2}",
row["firstname"].ToString(), row["lastname"].ToString(), row["city"].ToString());
}
三:将变化保存到数据源中
数据适配器如何用数据集中的数据更新和同步数据源。UpdateCommand, InsertCommand, DeleteCommand。
1: UpdateCommand
conn = new SqlConnection(@"
server=./sqlexpress; integrated security=true; database=northwind");
String sqlComTxt1 = "select * from employees where country = 'UK' ";
String sqlComTxt2 = "update employees set city = @city where employeeid = @employeeid";
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = new SqlCommand(sqlComTxt1, conn);
DataSet ds = new DataSet();
da.Fill(ds, "dstable");
DataTable dt = ds.Tables["dstable"];
dt.Rows[0]["city"] = "wilmingtom";
foreach (DataRow row in dt.Rows)
{
Console.WriteLine("{0}/t{1}/t{2}",
row["firstname"].ToString(), row["lastname"].ToString(), row["city"].ToString());
}
SqlCommand cmd = new SqlCommand(sqlComTxt2, conn);
cmd.Parameters.Add("@city", SqlDbType.NVarChar, 15, "city");
//默认情况是从数据表的当前版本中提取,所以city直接取就可以
//但是employeeid必须从修改之前的版本中提取值,这样,如果主键发生变化,就可以在数据库表中反问正确的行。
SqlParameter parm = cmd.Parameters.Add("@employeeid", SqlDbType.Int, 4, "employeeid");
parm.SourceVersion = DataRowVersion.Original;
//将变化保存到数据库中
//数据适配器会在dstable数据表中查找所有已修改的行,并把对它们的所有更新都提交给数据库
da.UpdateCommand = cmd;
da.Update(ds, "dstable");
2: InsertCommand
调用Update命令时,将搜索以前添加到表中的所有新行,并将其保存到数据库中。
conn = new SqlConnection(@"
server=./sqlexpress; integrated security=true; database=northwind");
String sqlComTxt1 = @"select * from employees where country = 'UK' ";
String sqlComTxt2 = @"insert into employees (firstname, lastname, titleofcourtesy, city, country)
values(@firstname, @lastname, @titleofcourtesy, @city, @country)";
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = new SqlCommand(sqlComTxt1, conn);
DataSet ds = new DataSet();
da.Fill(ds, "dstable");
DataTable dt = ds.Tables["dstable"];
DataRow dr = dt.NewRow();
dr["firstname"] = "Roy";
dr["lastname"] = "Beatty";
dr["titleofcourtesy"] = "Sir";
dr["city"] = "Birmingham";
dr["country"] = "UK";
dt.Rows.Add(dr);
foreach (DataRow row in dt.Rows)
{
Console.WriteLine("{0}/t{1}/t{2}",
row["firstname"].ToString(), row["lastname"].ToString(), row["city"].ToString());
}
SqlCommand cmd = new SqlCommand(sqlComTxt2, conn);
cmd.Parameters.Add("@firstname", SqlDbType.NVarChar, 10, "firstname");
cmd.Parameters.Add("@lastname", SqlDbType.NVarChar, 20, "lastname");
cmd.Parameters.Add("@titleofcourtesy", SqlDbType.NVarChar, 25, "titleofcourtesy");
cmd.Parameters.Add("@city", SqlDbType.NVarChar, 15, "city");
cmd.Parameters.Add("@country", SqlDbType.NVarChar, 15, "country");
//InsertCommand,会在dstable表中查找所有的新行,并把对它们的所有插入操作都提交给数据库
da.InsertCommand = cmd;
da.Update(ds, "dstable");
3: DeleteCommand属性
conn = new SqlConnection(@"
server=./sqlexpress; integrated security=true; database=northwind");
String sqlComTxt1 = @"select * from employees where country = 'UK' ";
String sqlComTxt2 = @"delete from employees where employeeid = @employeeid";
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = new SqlCommand(sqlComTxt1, conn);
DataSet ds = new DataSet();
da.Fill(ds, "dstable");
DataTable dt = ds.Tables["dstable"];
SqlCommand cmd = new SqlCommand(sqlComTxt2, conn);
cmd.Parameters.Add("@employeeid", SqlDbType.Int, 4, "employeeid");
//选择要删除的行,并删除它。由于不关心ID,所以直接删除名,同样的DeleteCommand命令中会反映出来
String filter = @"firstname = 'Roy' and lastname = 'Beatty'";
foreach (DataRow row in dt.Select(filter))
{
row.Delete();
}
//InsertCommand,会在dstable中查找所有的新行,并把它们的所有插入操作都提交给数据库
da.DeleteCommand = cmd;
da.Update(ds, "dstable");
foreach (DataRow row in dt.Rows)
{
Console.WriteLine("{0}/t{1}/t{2}",
row["firstname"].ToString(), row["lastname"].ToString(), row["city"].ToString());
}
4: 命令构建器
conn = new SqlConnection(@"
server=./sqlexpress; integrated security=true; database=northwind");
String sqlComTxt1 = @"select * from employees where country = 'UK'";
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = new SqlCommand(sqlComTxt1, conn);
SqlCommandBuilder scb = new SqlCommandBuilder(da);
DataSet ds = new DataSet();
da.Fill(ds, "dstable");
DataTable dt = ds.Tables["dstable"];
DataRow dr = dt.NewRow();
dr["firstname"] = "Roy";
dr["lastname"] = "Beatty";
dr["titleofcourtesy"] = "Sir";
dr["city"] = "Birmingham";
dr["country"] = "UK";
dt.Rows.Add(dr);
foreach (DataRow row in dt.Rows)
{
Console.WriteLine("{0}/t{1}/t{2}",
row["firstname"].ToString(), row["lastname"].ToString(), row["city"].ToString());
}
da.Update(ds, "dstable");
//注解:
SqlCommandBuilder scb = new SqlCommandBuilder(da);
//等价于:
String sqlComTxt2 = @"insert into employees (firstname, lastname, titleofcourtesy, city, country)
values(@firstname, @lastname, @titleofcourtesy, @city, @country)";
SqlCommand cmd = new SqlCommand(sqlComTxt2, conn);
cmd.Parameters.Add("@firstname", SqlDbType.NVarChar, 10, "firstname");
cmd.Parameters.Add("@lastname", SqlDbType.NVarChar, 20, "lastname");
cmd.Parameters.Add("@titleofcourtesy", SqlDbType.NVarChar, 25, "titleofcourtesy");
cmd.Parameters.Add("@city", SqlDbType.NVarChar, 15, "city");
cmd.Parameters.Add("@country", SqlDbType.NVarChar, 15, "country");
//使用
SqlConnection conn = new SqlConnection(strConnection));//连接数据库
SqlDataAdapter myAdapter = new SqlDataAdapter();//new一个adapter对象
SqlCommand myCommand = new SqlCommand("select * from "+strTblName),(SqlConnection) conn); //cmd
SqlCommandBuilder myCommandBuilder = new SqlCommandBuilder(myAdapter); //new 一个 SqlCommandBuilder
myAdapter.InsertCommand = myCommandBuilder .GetInsertCommand();//插入
myAdapter.UpdateCommand = myCommandBuilder .GetUpdateCommand();//更新
myAdapter.DeleteCommand = myCommandBuilder .GetDeleteCommand();//删除
conn.Open();//打开数据库
myAdapter.Update(ds); //更新ds到数据库
conn.Close();//关闭数据库
四:使用数据集和XML
XML是数据交换的基本格式,将数据从数据集写入XML文件中
conn = new SqlConnection(@"
server=./sqlexpress; integrated security=true; database=northwind");
String sqlComTxt1 = @"select productname, unitprice from products";
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = new SqlCommand(sqlComTxt1, conn);
conn.Open();
DataSet ds = new DataSet();
da.Fill(ds, "dstable");
ds.WriteXml("xml.xml");
//写入文件
<?xml version="1.0" standalone="yes" ?>
<NewDataSet>
<dstable>
<productname>Chai</productname>
<unitprice>18.0000</unitprice>
</dstable>
<dstable>
<productname>Chang</productname>
<unitprice>19.0000</unitprice>
</dstable>
</NewDataSet>
五:在没有数据集的情况下使用数据表
在只有一个表的情况下。
conn = new SqlConnection(@"
server=./sqlexpress; integrated security=true; database=northwind");
String sqlComTxt1 = @"select productname, unitprice from products where unitprice < 20";
conn.Open();
SqlDataAdapter da = new SqlDataAdapter(sqlComTxt1, conn);
DataTable dt = new DataTable();
da.Fill(dt);
foreach (DataRow row in dt.Rows)
{
foreach (DataColumn col in dt.Columns)
Console.WriteLine(row[col]);
Console.WriteLine();
}