ADO.NET 和 LINQ using DataSet
1.用DataReader读取数据
读取SQL数据库:
......
using System.Data; //使用ADO.NET名称空间
using System.Data.SqlClient; //使用SQL Server 数据提供者名称空间
......
SqlConnection thisConnection = new SqlConnection(@".......数据库连接字符串......."); //初始化连接对象,连接字符串因数据库连接而异
thisConnection.Open(); //打开连接
SqlCommand thisCommand = thisConnection.CreateCommand(); //建立命令对象,并初始化
thisCommand.CommandText = "SELECT CustomerIDs, CompanyName from Customers";
SqlDataReader thisReader = thisCommand.ExecuteReader(); //创建DataReader对象,并执行读取命令
while(thisReader.Read()) //判断是否有读到数据
{
Console.WriteLine("/t{0}/t{1}", thisReader["CustomerID"],thisReader["CompanyName"]);
}
thisReader.Close(); //关闭DataReader对象
thisConnection.Close(); //关闭连接
*****************************************
读取Access数据库:
......
using System.Data; //使用ADO.NET名称空间
using System.Data.OleDb; //使用OLE DB .NET的名称空间
......
OleDbConnection thisConnection = new OleDbConnection(@"......数据库连接字符串.......");
thisConnection.Open();
OleDbCommand thisCommand = thisConnection.CreateCommand();
thisCommand.CommandText = "SELECT CustomerID, CompanyName FROM Customers";
OleDbDataReader thisReader = thisCommand.ExecteReader();
while(thisReader.Read())
{
Console.WriteLine("/t{0}/t{1}",thisReader["CustomerID"],thisReader["CompanyName"]);
}
thisReader.Close();
thisConnection.Close();
________________
2.用DataSet读取数据
.......
using System.Data;
using System.Data.SqlClient;
.......
SqlConnection thisConnection = new SqlConnection(@"....数据库连接字符串....");
SqlDataAdapter thisAdapter = new SqlDataAdapter("SELECT CustomerID, ContactName FROM Customers", thisConnection); //初始化DataAdapter对象
DataSet thisDataSet = new DataSet();
thisAdapter.Fill(thisDataSet, "Customers"); //填充DataSet对象,第一个参数是要填充的DataSet对象,第二个参数是DataSet所包含的表的名称。
foreach(DataRow theRow in thisDataSet.Table["Customers"].Rows)
{
Console.WriteLine(theRow["Customers"] +"/t"+theRow["ContactName"]);
}
thisConnection.Close();
DataSet的属性:
DataSet包含一组DataTable对象,DataTable对象有一些子对象DataRow 和 DataColumn,表示行和列。
Tables属性:
它是DataSet中所有DataTable对象的集合;
类型是DataTableCollection
有两种方式访问每个DataTable:
1)按表名访问,如:thisDataSet.Tables["Customers"]指定DataTable对象Customers;
2)按索引访问:如:thisDataSet.Tables[0]指DataSet中第一个DataTable。
DataTable的Rows属性:
它是DataRow对象的集合。
类型是DataRowCollection,是一个有序列表,按行号排序。
myDataSet.Tables["Customers"].Rows[n]
访问列:
DataRow没有Columns属性。但可以按列名访问:
thisDataSet.Tables["Customers"].Rows[n]["CompanyName"],其中CompanyName就是列名。
DataRow对象有个索引属性,可以按名称 和 列号访问个列,如:theRow["CustomerID"]访问DataRow对象theRow的CustomerID列。
DataAdapter不改变数据库连接的状态。如果工作开始前连接时打开的,那么结束后也是打开的;如果是关闭的,结束后也是关闭的。
所有,没有连接没有明确的打开和关闭连接。
________________
3. 更新数据库
数据库的 修改、插入、删除的步骤:
1)填充DataSet;
2)修改DataSet数据;
3)把DataSet数据返回到数据库。
修改行:
例:
SqlConnection thisConnection = new SqlConnection(@".........ConnectString............");
SqlAdapter thisAdapter = new SqlAdapter("SELECT CustomerID, CompanyName FROM Customers", thisConnection);
SqlCommandBuilder thisBuilder = new SqlCommandBuilder(thisAdapter); //SqlCommandBuilder创建SQL命令,并与thisAdapter关联
thisAdapter.Fill(thisDataSet, "Customers");
......
thisDataSet.Tables["Customers"].Rows[9]["CompanyName"] = "Acme, Inc."; //修改DataSet数据
thisAdapter.Update(thisDataSet, "Customers"); //更新数据库
thisConnection.Close();
SqlCommandBuilder生成SQL命令,包括增、删、改。SqlAdapter.Update()执行时,根据具体情况(增删改数据)执行相应的操作。
DataRow类的RowState属性会追踪 行有什么变动,做为Update()执行的依据。
添加行:
例:
.......
thisAdapter.Fill(thisDataSet, "Customers"); //之前的代码与上例一样
.......
//在DataSet中加入新行
DataRow thisRow = thisDataSet.Tables["Customers"].NewRow(); //用Tables["Customers"]的DataRow结构,初始化DataRow。
thisRow["CustomerID"] = "ZZ099";
thisRow["CompanyName"] = "Ares Lab";
thisDataSet.Tables["Customers"].Rows.Add(thisRow); //将新建的DataRow加入到DataSet中
thisAdapter.Update(thisDataSet, "Customers");
thisConnection.Close();
删除行:
先要查找行,然后删除。
例:
......Fill DataSet & SqlCommandBuild ......
DataColume[] keys = new DataColumn[1]; //创建DataColumn数组,因为键可以由多列组成
keys[0] = thisDataSet.Tables["Customers"].Columns["CustomerID"]; //为键数组赋值
thisDataSet.Tables["Customer"].PrimaryKey = keys; //设置主键,查找行时,通过主键查找
DataRow findRow = thisDataSet.Tables["Customers"].Rows.Find("ZZ009"); //查找行
if(finRow != null)
findRow.Delete(); //在DataSet中删除行。 Delete()会标记RowState属性,并不执行删除操作。
//当希望从DataSet中删除行,而不是数据库中删除时,用Remove()方法。
thisAdapter.Update(thisDataSet, "Customers");
thisConnection.Close();
设置主键的另一种方式:
直接从数据库中加载主键,通过设置DataAdapter的MissingSchemaAction属性。
thisAdapter.MissingSchemaAction = MissingSchemaAction.AddWithKey; //这行,通过隐式初始化DataTable的PrimaryKey属性,完成主键的设置。
thisAdapter.Fill(thisDataSet, "Customers");
________________
4. 在DataSet中访问多个表
DataSet的DataRelation对象,可以跟踪多个表之间的关系。
DataRelation对象用于描述多个DataTable对象之间的关系。DataRelation对象的集合包含在Relations属性中。
要创建DataRelation对象,可以用Relation的Add()方法。
例:
.....
using System.Data;
using System.Data.SqlClient;
.......// 前面的代码省略了
custAdapter.Fill(thisDataSet, "Customers"); //把Orders &Customer表填充到DataSet中
orderAdapter.Fill(thisDataSet, "Orders");
DataRelation custOrderRel = thisDataSet.Relations.Add("CustOrders", //第一参数:关系命名
thisDataSet.Tables["Customers"].Columns["CustomerID"], //第二参数:父表的关联字段
thisDataSet.Tables["Orders"].Columns["CustomerID"]); //第三参数:子表的关联字段
foreach(DataRow custRow in thisDataSet.Tables["Customers"].Rows)
{
Console.WriteLine("Customer ID: " + custRow["CustomerID"]);
foreach(DataRow orderRow in custRow.GetChildRows(cusrOrderRel)) //custRow是父表中的一行,由GetChildRows方法依据custOrderRel关系,
{ //在子表中查找的相关行。
Console.WriteLine(" Order ID: " + orderRow["OrderID"]);
}
}
使用GetParentRow()获取与此关联的父对象。
________________
5. ADO.NET DataSet中的XML支持
ADO.NET中XML支持主要集中于DataSet对象,因为XML主要关注的是关系 和 分层的结构化数据。
从DataSet中写入XML:
1)构造一个DataSet;
2)DataAdapter对象的Fill()方法加载数据;
3)DataSet上调用WriteXml(),比如:thisDataSet.WriteXml("AresData.Xml");
例:
.......
custOrderRel.Nested = true; //DataRelation对象的Nested属性通知将相关表,嵌套在XML输出中每个父客户之下。
thisDataSet.WriteXml(@"c:/..../AresData.xml"); //调用WriteXml(),将DataSet数据按XML格式写入文件中。
从XML读取到DataSet中:
.......
DataSet thisDataSet = new DataSet();
thisDataSet.ReadXml(@"c:/..../AresData.xml"); //ReadXml()方法读取XML文档到thisDataSet对象中。
foreach(DataRow custRow in thisDataSet.Tables["Customers"].Rows) //所创建的DataTable采用XML文档中的根元素命名。
{ //可以使用DataTable的TableName属性,输出DataSet的DataTable名称。如:thisDataSet.Tables[0].TableName.
Console.WriteLine(custRow["CustomerID"]);
}
________________
6. 带有WHERE 的SELECT
SELECT * FROM Customers WHERE CustomerID = "ZZ009"
SELECT * FROM Orders WHERE OrderID BETWEEN 10900 AND 10999
________________
7.DataAdapter 对象中的SQL命令
注:ADO.NET对象模型 和 C# 要比 SQL 更适合处理复杂运算 和 导航逻辑(比如,查找相关的另一个表的数据)
所以,可以把数据填充到DataSet中,在客户机上执行这种逻辑。
查看SQL SELECT、UPDATE、INSERT 和 DELETE命令:
命令构建器(command builder)用于根据SELECT命令生成SQL命的UPDATE、INSERT和DELETE)命令。
可以用CommandBuilder对象的GetUpdateCommand()、GetInsertCommand()和GetDeleteCommand()方法生成命令。
例:
SqlConnection thisConnection = new SqlConnection(@".........ConnectString...........");
thisConnection.Open();
SqlDataAdapter thisAdapter = new SqlDataAdapter("SELECT CustomerID FROM Customers", thisConnection);
SqlCommandBuilder thisBuilder = new SqlCommandBuilder(thisAdapter); //用Command builder构建命令
SqlCommand updateCommand = thisBuilder.GetUpdateCommand();
Console.WriteLine(updateCommand.CommandText); // 输出builder构建的SQL命令,可以看到SQL命令是什么样的,
//比如:UPDATE [Customer] SET [CustomerID] = @p1 WHERE ......
SqlCommand insertCommand = thisBuilder.GetInsertCommand();
Console.WriteLine(insertCommand.CommandText);
SqlCommadn deleteCommand = thisBuilder.GetDeleteCommand();
Console.WriteLine(deleteCommand.CommandText);
DataAdapter还有SelectCommand,UpdateCommand,InsertCommand和DeleteCommand属性,可以直接获取 和 设置 更新时使用的SQL命令。
________________
8.直接执行SQL命令
执行面向集合的操作(比如,更新满足条件的一组数据)可以直接用SQL命令,要比用C#扩展的SQL指令更有效。
ADO.NET 提供了 SqlCommand 和 OleDbCommand对象,他们提供了可直接执行SQL命令的方法。
提取单值:
例:
.....
SqlConnection thisConnection = new SqlConnection(@".........ConnectString.........");
thisConnection.Open();
SqlCommand thisCommand = thisConnection.CreateCommand();
thisCommand.CommandText = "SELECT COUNT (*) FROM Customers ";
Object countResult = thisCommand.ExecuteScalar();
Console.WriteLine(countResult); //输出查询到的记录数目
thisConnection.Close();
不检索数据:
类似SQL INSERT, UPDATE, DELETE的修改操作不需要返回数据,只需要知道影响的行数。
用ExecuteNonQuery()方法。
例:
......
thisCommand.CommandText = "UPDATE Products SET UnitPrice=UnitPrice*1.05 WHERE SupplierId=12";
int rowAffected = thisCommand.ExecuteNonQuery(); //执行后,只返回影响的行数
Console.WriteLine(rowAffected);
thisConnection.Close();
________________
9.调用SQL存储过程
存储过程在一个单元中封装了复杂的SQL查询和数据过程,可以由多个程序或用户之间调用。
例:
......
SqlConnection thisConnection = new SqlConnection(@"...........ConnectionString..............");
thisConnection.Open();
SqlCommand thisCommand = thisConnection.CreateCommand();
thisCommand.CommandType = CommandType.StoredProcedure; //将SqlCommand对象的命令属性设为 存储过程类型。
//CommandType.StoreProcedure是ADO.NET的一个枚举
thisCommand.CommandText = "Ten Most Expensive Products"; //"Ten Most Expensive Products"是一个存储过程的名称
SqlDataReader thisReader = thisCommand.ExecuteReader();
while(thisReader.Read())
Console.WriteLine(thisReader[UnitePrice]); //UnitePrice是列名
________________
10.使用LINQ over DataSet
LINQ over DataSet工具联合使用LINQ 和 ADO.NET。是LINQ to Entity(属于高级内容)功能的一小部分。
它使用System.Data.DataSetExtensions名称空间,由VS自动添加。不需要手动using,只要using System.Data.Linq。
例:
.....
//ADO.NET代码
........
custAdapter.Fill(thisDataSet, "Customers"); //用ADO.NET填充
orderAdapter.Fill(thisDataSet,"Orders");
DataRelation custOrderRel = thisDataSet.Relations.Add("CustOrders", //建立表Orders 和 Customers之间的关系
thisDataSet.Tables["Customers"].Columns["CustomerID"],
thisDataSet.Tables["Orders"].Columns["CustomerID"]);
//下面是LINGQ代码
var customers = thisDataSet.Tables["Customers"].AsEnumerable(); //将表赋值给var对象
var orders = thisDataSet.Tables["Orders"].AsEnumerable();
var preferredCustomers = //用LINQ查询数据
from c in customers
where c.GetChildRows("CustOrders").Length»10
orderby c.GetChildRows("CustOrders").Length
select c;
foreach(var customer in preferredCustomers)
{
Console.WriteLine("{0} orders: {1} {2}",
customer.GetChildRows("Custorders").Length,
customer["CustomerID"], customer["CompanyName"]);
}
________________
LINQ to XML
LINQ to XML并不打算替代标准的XML API,只是补充了这些标准XML类
11.LINQ to XML函数构造方法
函数构建方式(functional construction):
在这种方式中,构造函数的调用可以用反映XML文档结构的方式嵌套。
例:
.....
XDocument xdoc = new XDocument( //XCocument 表示完整的XML文档
new XELement("customers",
new XElement("customer",
new XAtrribute("ID","A"),
new XAtrribute("City","New York"),
new XAtrribute("Region","North America"),
new XElement("order",
new XAtrribute("Item","Widget"),
new XAtrribute("Price",100)
)
),
new XElement("customer",
"AAAAA",
new XAtrribute("ID","B"),
new XAtrribute("City","Mumbai")
)
);
Console.WriteLine(xdoc);
Console.ReadLine();
.....
输出结果:
«customers»
«customer ID="A" City="New York" Region="North America"»
«order Item="Widget" Price="100" /»
«/cutomer»
«customer ID="B" City="Mumbai" Region="Asia"»AAAAA«/customer»
«/customers»
*********************************
XML的属性是叶节点,所以不包含其他节点,只有属性名称和值.
其他构造函数:XDeclaration()用于XML文档开头的声明; XComment()用于XML注释。
________________
12.保存和加载XML文档
Save()方法&Load()方法:
在用LINQ to XML方法Save()把XML文档保存到文件时,会自动创建文档开头的声明,一般不需要用XDeclaration()来创建。
XDocument.Load()是静态的,可以加载由别的程序创建的文档,创建XDocument实例。
例:
XDocument xdoc = new XDocument(..............);
string xmlFileName = @"C:/....../example.xml";
xdoc.Save(xmlFileName); //将构造好的XML文档,存储为文件
XDocument xdoc2 = XDocument.Load(xmlFileName); //将磁盘中的文档读取出来
Cosole.WriteLine(xdoc2);
......
从字符串加载XML:
XDocument xdoc = XDocument.Parse(@"«customers».......«/customers»"); //Parse通过字符串创建XML文档
声明一个ASCII码的XML文档头:
xdoc.Declaration = new XDeclaration("1.0","us-ascii","yes");
________________
13.处理XML片段
处理片段时,只是把XElement(而不是XDocument)当作顶级XML对象。
片段的唯一限制是,不能添加比较节点类型,例如:XComment,XDeclaration,XProcessingInstruction(用于XML处理指令)。
例:
XElement xcust = new XElement( new XElement(......)..........);
注意:这两个类都实现了Load()和Save()方法,XElemnt 和 XDocument继承自LINQ to XML类的XContainer;
在XDocument上执行的大多数操作,在XElement上也可以执行。
________________
14.通过LINQ to XML生成 XML
XML常常用语在客户机和服务器之间交流数据,或者多层应用程序之间交流。
用LINQ to SQL查询数据,再用LINQ to XML吧数据转换为XML.
例:
.......
AreslabDataContext aresData = new aresData(); //创建DataContext实例
XElement aresCustomerOrders = new XElement("customers", //创建XML片段实例
from c in aresData.Customers //利用LINQ查询数据,DataContext对象的Customers成员作为数据源
select new XElement("customer", //构建select投射
new XAtrribute("ID", c.CustomerID),
new XAtrribute("Company", c.CompanyName),
from o in c.orders
select new XElement("order",
new XAtrribute("orderID",o,OrderID),
new XAtrribute("orderTotal", o.Order_Detail.Sum(od=»od.Quantity*od.UnitPrice))
) //end order
) //end customer
); //end customers
string xmlFileName = "c:/.../aresCustomerOrders.xml";
aresCustomerOrders.Save(xmlFileName);
________________
15.查询XML文档
LINQ to XML类提供属性和方法,返回可查询的类的对象集合。
将XML对象作为LINQ查询对象:
.......
XDocument customers = XDocument.Load(xmlFileName);
var queryResult = from c in customers.Elements() select c.Name;
使用查询成员
1)Element():返回文档 或 片段中的第一个元素。文档的话就返回根元素;
2)Descendants():返回文档 或 片段中的所有子元素(所有级别);
例:queryResults = from c in customers.Descendants() select c.Name;
foreach (var item in queryResults.Distinct()) //筛选出不同的元素
Descendants(string)重载:
queryResults = from c in customers.Desendants("customer") select c; //查询指定名称的子元素,返回所有customer元素。
3)Ancestors():返回比源元素级别高的一组元素;
4)Attribute():返回当前选中元素的所有属性;
例:queryResults = from c in customers.Descendants("customer").Attributes() select c; //返回customers中所有customer元素的属性值
显示c的话是:ID City Company ....ID City Company.............
Attribute(sting)重载:
queryResults = from c in customers.Descendants("customer").Attribute("Company")//返回指定属性对象:Company=“Toms Spezialit”
select c.Value; //用Value属性获得属性值
int min = queryResults.Min(); //取记录中的最小值
________________