ADO ( ActiveX Data Objects ).NET
是与C#和.NET Framework一起使用的类集的名称,用于以关系型的、面向表的格式访问数据
ADO是一个COM组件库
ADO.NET的主要特点
不依赖于连续的活动连接
使用数据命令执行数据库交互
使用数据集缓存数据
数据集独立于数据源
数据保持为XML
通过架构定义数据结构
ADO.NET对象模型的结构
Connection对象表示与一个数据源的物理连接
DataAdapter是Connection与数据集之间的桥梁
DataAdapter管理了4个Command对象来处理后端数据集和数据源的通信,即SelectCommand、UpdateCommand、InsertCommand、DeleteCommand
DataReader对象用于从数据源中获取仅前向、只读的数据流
数据集
数据集中的数据可能来自多个数据源
ADO.NET支持外键约束和唯一键约束
OLEDB模式
是微软开发的一种高性能的基于COM的数据库技术
OLEDB数据提供程序通过OleDbConnection对象提供了与使用OLEDB公开数据源的连接,以及与Microsoft SQL Server 6.X或以前版本的连接
ODBC模式
主要用于连接ODBC所支持的数据库
是微软联合其他数据库厂商开发出的一种通用数据库访问技术
SQLClient模式
只用于访问MS SQL Server数据库
Connection连接字符串
用于提供登录数据库和指向特定数据库所需的信息
Provider=SQLOLEDB; Data Source=MySQLServer;
Initial Catalog=MyDB; Integrated Security=SSPI;
连接字符串可以改为通过用户名和密码来登录,但可能对安全性造成潜在威胁
与SQL Server数据库的连接
使用SqlClient方式
data source=127.0.0.1; persist security info=false;
initial catalog=MyDB; integrated security=SSPI;
使用OleDb方式
Provider=SQLOLEDB; data source=127.0.0.1; persist security
info=false; initial catalog=MyDB; integrated security=SSPI;
使用Odbc方式
Driver ={SQL Server}; Server=127.0.0.1; Database=MyDB;
Trusted_Connection=Yes; UID=Administrator
与Access数据库的连接
OleDb方式
Provider=Microsoft.Jet.OLEDB.4.0; User ID=Admin;
Data Source=c:\data.mdb
Odbc方式
Driver={Microsoft Access Driver (*.mdb) };
DBQ=C:\data.mdb; UID=admin;
要定义数据库连接字符串,应使用配置文件中部分。在这里可以指定连接的名称、数据库连接字符串的实际参数,还需要指定这个连接类型的提供程序
private DbConnection GetDatabaseConnection (string name)
{
ConnectionStringSettings settings = ConfigurationManager.ConnectionStrings[name];
DbProviderFactory factory = DbProviderFactories.GetFactory(settings.ProviderName);
DbConnection conn = factory.CreateConnection();
conn.ConnectionString = settings.ConnectionString;
return conn;
}
首先读取指定的连接字符串段(使用ConfigurationStringSettings类)
再从基类DbProviderFactories中申请一个提供程序工厂,这要使用ProviderName属性,它在应用程序配置文件中设置为“System.Data.SqlClient”。
它会映射为实际的工厂类,用于为SQL Server生成数据库连接
System.Data.OleDb.OleDbConnection conn= new System.Data.OleDb.OleDbConnection
(“Provider=Microsoft.Jet.OLEDB.4.0; User ID=Admin; Data Source=c:\\data.mdb; ”);
System.Data.OleDb.OleDbConnection conn= new System.Data.OleDb.OleDbConnection( );
conn.ConnectionString=“Provider=Microsoft.Jet.OLEDB.4.0; User ID=Admin; Data Source=c:\\data.mdb; ”;
过多的连接会白白消耗服务器资源
try
{
conn.Open( );
……
}
catch ( Exception ex )
{
……
}
finally
{
conn.Close( );
}
string connString=“Provider=Microsoft.Jet.OLEDB.4.0;
User ID=Admin; Data Source=c:\\data.mdb;”;
try
{
using (OleDbConnection conn=new OleDbConnection(connString))
{
con.Open();
……
}
}
catch (SqlException ex)
{
……
}
StateChange事件发生在Connection对象状态改变后,传递一个StateChangeEventArgs对象给它的处理程序
StateChangeEventArgs对象有两个属性:OriginalState和CurrentState
string connString=“data source=127.0.0.1;”+
“persist security info=false;”+”initial catalog=MyDB;”+
“integrated security=SSPI;”;
SqlConnection conn=new SqlConnection(connString);
SqlTransaction tx;
try
{
conn.Open( );
tx=conn.BeginTransaction();
……
tx.Commit( );
}
catch ( Exception ex )
{
tx.Rollback( );
}
finally
{
conn.Close( );
}
TransactionScope类可以把几个事务方法合并到一个事务范围中,事务流会根据需要执行每个方法,并将它们当做原子操作
string source=“server=(local);”+”integrated security
=SSPI;” +”database=Northwind”;
using (TransactionScope scope=new TransactionScope
(TransactionScopeOption.Required)) {
using (SqlConnection conn=new SqlConnection(source))
{
// Do something in SQL
……
//Then mark complete
scope.Complete();
}
}
Command对象的创建
public SqlCommand ()
public SqlCommand ( string cmdText, SqlConnection connection )
public SqlCommand ( string cmdText, SqlConnection connection, SqlTransaction transaction )
Command对象的属性
CommandText
包含要执行的SQL语句或数据源中存储过程的名字
Connection
指定执行数据操作的数据源
Transaction
指定执行数据命令登记的事务对象
CommandTimeout
数据命令出错前等待服务器响应的时间
CommandType
决定Command对象如何解释CommandText属性的内容
Parameters
CommandText属性指定的SQL语句或存储过程的参数集合
UpdatedRowSource
决定在Command对象执行存储过程时如何使用输出参数
执行数据命令
public override int ExecuteNonQuery ()
执行一个命令但不返回结果集。这个方法一般用于Update、Insert或Delete语句,其中唯一的返回值是受影响的记录个数。 但如果调用带输出参数的存储过程,该方法就有返回值
public SqlDataReader ExecuteReader ()
执行一个命令并返回一个DataReader对象
public abstract Object ExecuteScalar ()
执行一个命令并返回一个值
public XmlReader ExecuteXmlReader ()
执行一个命令,返回一个XmlReader对象,它可以遍历从数据库中返回的XML片段
static void Main(string[] args)
{
string connString=@"Provider=Microsoft.Jet.OLEDB.4.0;
Data Source=E:\db1.mdb";
OleDbConnection conn=new OleDbConnection (connString);
conn.Open();
string sqlString="update student set 年龄=28 where 姓名='John';";
OleDbCommand cmd=new OleDbCommand(sqlString,conn);
int r=cmd.ExecuteNonQuery();
Console.WriteLine("{0} 记录已更新",r);
Console.ReadKey();
conn.Close();
}
static void Main(string[] args)
{
string connString = "data source=127.0.0.1;" + "persist security
info=false;" + "initial catalog=mydb;" + "integrated security=SSPI;";
SqlConnection conn = new SqlConnection(connString);
conn.Open();
SqlCommand cmd = new SqlCommand("insert_teacher", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("@teacher_name",
SqlDbType.VarChar, 20, "name"));
cmd.Parameters.Add(new SqlParameter("@teacher_age",
SqlDbType.Int, 10, "age"));
cmd.Parameters.Add(new SqlParameter("@result", SqlDbType.Int, 10, ParameterDirection.Output, false, 0, 0, "age", DataRowVersion.Default, null));
cmd.UpdatedRowSource = UpdateRowSource.OutputParameters;
cmd.Parameters["@teacher_name"].Value = "张强";
cmd.Parameters["@teacher_age"].Value = 32;
cmd.ExecuteNonQuery();
Console.WriteLine("教师年龄的最大值是", cmd.Parameters["@result"].Value);
conn.Close();
}
UpdateRowSource值
Both 存储过程可以返回输出参数和一个完整的数据库记录。这两个数据源都用于更新源数据行
FirstReturnedRecord 该命令返回一个记录,该记录的内容应合并到最初的源DataRow中,当给定的表有许多默认(或计算)列时,使用这个值很有用,因为在执行insert语句之后,这些行需要与客户端上的DataRow同步。
None 丢弃从该命令返回的所有数据
OutputParameters 命令的任何输出参数都映射到DataRow的对应列上
使用UpdatedRowSource将值映射到数据集
通过使用DbCommand的UpdatedRowSource属性,可以在调用DataAdapter的Update方法后控制从数据源返回的值映射回DataTable的方式
通过将UpdatedRowSource属性设置为UpdateRowSource枚举值之一,您可以控制是忽略由DataAdapter命令返回的输出参数还是将其应用于DataSet中已更改的行
还可以指定是否将返回的第一行(如果存在)应用于DataTable中已更改的行
static void Main(string[] args)
{
string connString=@"Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=E:\db1.mdb";
string sqlString = "select count(*) from student";
OleDbConnection conn = new OleDbConnection(connString);
conn.Open();
OleDbCommand cmd = new OleDbCommand(sqlString, conn);
Object o = cmd.ExecuteScalar();
Console.WriteLine("记录数为:{0}", o);
Console.ReadKey();
conn.Close();
}
用DataReader读取数据
static void Main(string[] args)
{
OleDbConnection thisConnection = new OleDbConnection(
@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=E:\db1.mdb");
thisConnection.Open();
OleDbCommand thisCommand = thisConnection.CreateCommand();
thisCommand.CommandText =
"SELECT 姓名, 年龄 FROM student";
OleDbDataReader thisReader = thisCommand.ExecuteReader();
while (thisReader.Read())
{
Console.WriteLine("\t{0}\t{1}",
thisReader["姓名"], thisReader["年龄"]);
}
thisReader.Close();
thisConnection.Close();
Console.Write("Program finished, press Enter/Return to continue:");
Console.ReadLine();
}
使用DataAdapter与DataSet
DataSet
类似于一个在客户机内存中的数据库,可以在这个数据库中增删表、定义表结构和关系、增删行
DataSet不考虑其中的表结构和数据是来自数据库、XML文件还是程序代码
DataSet的主要属性
Tables
数据集中数据表的集合,是一个DataTableCollection集合类
Relations
数据集中数据关系的集合,是一个DataRelationCollection集合类
ExtendedProperties
与DataSet相关的自定义用户信息的集合
HasErrors
判断DataSet中的任一DataTable对象中是否存在错误
DataSetName
当前数据集的名称
CaseSensitive
字符串比较是否区分大小写
Locale
数据表中字符串的区域设置信息
DataTable的构造方法
public DataTable ()
public DataTable ( string tableName )
DataTable的属性
Columns 属于该表的列的集合
Rows 该表的行的集合
PrimaryKey 表主键的列数组
MinimumCapacity 表的初始大小
ParentRelations、ChildRelations
表的父子关系的集合
DataColumn的构造方法
public DataColumn ()
创建一个默认DataColumn类实例
public DataColumn ( string columnName )
创建一个DataColumn实例并设定列名
public DataColumn ( string columnName, Type dataType )
创建一个DataColumn实例并设定列名与列类型
DataColumn的常用属性
ColumnName
指定列名
DataType
指定该列的数据类型
Expression
为该列指定一个表达式字符串
ColumnMapping
指定该列和XML元素的映射方式
AllowDBNull
指定该列是否允许空值
Caption
设置列标题
Ordinal
获取在集合中的位置(索引)
ReadOnly
指定该列是否不允许修改
Unique
指定该列值是否唯一
DefaultValue
指定在创建新行时该列的默认值
MaxLength
文本列的最大长度
AutoIncrement、AutoIncrementStep、AutoIncrementSeed
指定添加新行时该列的值是否自动递增、增量的大小和起始值
DataTable dataTable1=new DataTable( );
dataTable1.TableName=“Score”;
DataColumn dataColumn1=new DataColumn( );
DataColumn dataColumn2=new DataColumn( );
DataColumn dataColumn3=new DataColumn( );
dataColumn1.Caption=“学号”;
dataColumn1.ColumnName=“studentno”;
dataColumn1.MaxLength=8;
dataColumn2.Caption=“课程号”;
dataColumn2.ColumnName=“courseno”;
dataColumn2.MaxLength=8;
dataColumn3.Caption=“成绩”;
dataColumn3.ColumnName=“score”;
dataColumn3.DataType=typeof(Single);
DataColumn[] cols=new DataColumn[3];
cols[0]=dataColumn1;
cols[1]=dataColumn2;
cols[2]=dataColumn3;
dataTable1.Columns.AddRange(cols);
DataRow类的RowState属性
DataRowState.Added 已添加
DataRowState.Deleted 已删除
DataRowState.Detached 已创建
DataRowState.Modified 已修改
DataRowState.Unchanged 未更改
DataRow类的Version值
Current 列中目前存在的值,如果没有进行编辑,该值与初值相同。如果进行了编辑,该值就是最后输入的有效值,处于deleted状态的行不存在该版本
Original 最初从数据库中选择出来的列值。如果调用DataRow类的AcceptChanges方法,该值就更新为Current。处于added状态的行不存在该版本。
Proposed 如果在行上调用BeginEdit()方法并进行修改,每一列都会有一个推荐值,直到调用EndEdit()或CancelEdit()为止。处于Detached状态的行存在该版本,对于正在编辑的行也存在该版本。
Default 默认值(换言之,列的任何默认设置)处于Added、Modified或Unchanged状态的行的默认版本是current,处于deleted行的版本是默认版本是original,处于detached行的默认版本是Proposed(如果是被删除行不存在版本,如果是插入行的版本为proposed)
foreach (DataRow row in ds.Tables[“Customers”].Rows)
{
foreach (DataColumn dc in ds.Tables[“Customers”].Columns)
{
Console.WriteLine(“{0} Current={1}”,dc.ColumnName,
row[dc,DataRowVersion.Current]);
Console.WriteLine(“Default={0}”,
row[dc,DataRowVersion.Default]);
Console.WriteLine(“ Original={0}”,
row[dc,DataRowVersion.Original]);
}
}
一般在成功更新数据源之后调用AcceptChanges()方法
如果对数据进行许多修改,需要使用BeginEdit()和EndEdit()方法
在对DataRow中的列进行了修改后,就会在该行的DataTable上引发ColumnChanging事件
如果在修改前调用BeginEdit()方法,就不会发生ColumnChanging事件,于是可以进行多次修改,再调用EndEdit()方法,持久化这些修改
如果要回退到初值,就应调用CancelEdit()
添加记录行
DataRow row1=dataTable1.NewRow( );
row1[0]=“21010101”;
row1[1]=“2112105”;
row1[2]=“80.0”;
dataTable1.Rows.Add(row1);
dataTable1.AcceptChanges( );
或 DataRow r=ds.Tables[“Region”].Rows.Add(new Object[]
{“21010101”,”2112105”, “80.0”});
查找记录行
DataRow findrow=dataTable1.Rows.Find(“21010102”);
if (findrow != null)
{
……
}
修改记录行
DataRow row=dataTable1.Rows[0];
row.BeginEdit( );
row[“score”]=“92.3”;
row.EndEdit( );
row.AcceptChanges( );
删除记录行
DataRow row=dataTable1.Rows[0];
row. Delete( );
row.AcceptChanges( );
或
dataTable1.Rows.Remove(row);
DataAdapter对象表示一组数据命令和一个数据库连接,用于填充DataSet和更新数据源
作为DataSet和数据源之间的桥接器,通过映射Fill向DataSet填充数据,通过Update向数据库更新数据集的变化
static void Main(string[] args) {
OleDbConnection thisConnection = new OleDbConnection(
@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=E:\db1.mdb");
OleDbDataAdapter thisAdapter = new OleDbDataAdapter(
"SELECT * FROM student", thisConnection);
DataSet thisDataSet = new DataSet();
thisAdapter.Fill(thisDataSet, "MyStudent");
foreach (DataRow theRow in thisDataSet.Tables["MyStudent"].Rows)
{
Console.WriteLine(theRow["姓名"] + "\t" + theRow["年龄"]);
}
thisConnection.Close();
Console.Write("Program finished, press Enter/Return to continue:");
Console.ReadLine();
}
在数据适配器上使用存储过程
create procedure RegionSelect as
set nocount off
select * from Region
Go
private static SqlCommand GenerateSelectCommand
(SqlConnection conn)
{
SqlCommand aCommand=new SqlCommand(“RegionSelect”,
conn);
aCommand.CommandType=CommandTye.StoredProcedure;
aCommand.UpdatedRowSource=UpdateRowSource.None;
return aCommand;
}
使用数据集读取数据
static void Main(string[] args) {
OleDbConnection thisConnection = new OleDbConnection(
@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=E:\db1.mdb");
OleDbDataAdapter thisAdapter = new OleDbDataAdapter(
"SELECT * FROM student", thisConnection);
DataSet thisDataSet = new DataSet();
thisAdapter.Fill(thisDataSet, "MyStudent");
foreach (DataRow theRow in thisDataSet.Tables["MyStudent"].Rows)
{
Console.WriteLine(theRow["姓名"] + "\t" + theRow["年龄"]);
}
thisConnection.Close();
Console.Write("Program finished, press Enter/Return to continue:");
Console.ReadLine();
}
在数据适配器上使用存储过程
create procedure RegionSelect as
set nocount off
select * from Region
Go
private static SqlCommand GenerateSelectCommand (SqlConnection conn)
{
SqlCommand aCommand=new SqlCommand(“RegionSelect”, conn);
aCommand.CommandType=CommandTye.StoredProcedure;
aCommand.UpdatedRowSource=UpdateRowSource.None;
return aCommand;
}
DataSet ds=new DataSet();
SqlDataAdapter da=new SqlDataAdapter();
da.SelectCommand=GenerateSelectCommand(conn);
da.Fill(ds,”Region”);
从XML中填充DataSet类
DataSet还可以读写本地XML中的数据,如磁盘上的文件、数据流或文本读取器
DataSet ds=new DataSet();
ds.ReadXml(“.\\MyData.xml”);
用数据库中要使用的数据填充dataset
修改存储在dataset中的数据
完成了所有的修改操作后,把dataset中这些修改的内容返回到数据库中
static void Main(string[] args)
{
OleDbConnection thisConnection = new
OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=E:\db1.mdb");
OleDbDataAdapter thisAdapter = new OleDbDataAdapter(
"SELECT * FROM student", thisConnection);
OleDbCommandBuilder thisBuilder = new OleDbCommandBuilder(thisAdapter);
//负责生成用于更新数据库的SQL语句,不必自己创建这些语句
DataSet thisDataSet = new DataSet();
thisAdapter.Fill(thisDataSet, "Stu");
Console.WriteLine("age before change: {0}",
thisDataSet.Tables["Stu"].Rows[0]["年龄"]);
thisDataSet.Tables["Stu"].Rows[0]["年龄"] = 18;
thisAdapter.Update(thisDataSet, "Stu");
//遍历DataTable中的行,找出需要对数据库作出的变动
Console.WriteLine("age after change: {0}",
thisDataSet.Tables["Stu"].Rows[0]["年龄"]);
thisConnection.Close();
Console.Write("Program finished, press Enter/Return to continue:");
Console.ReadLine();
}
给数据库添加行
创建一个新的DataRow
给它填充数据
把它添加到DataSet的Rows集合中
调用DataAdapter对象的Update( )方法,把这个变化返回到数据库中
static void Main(string[] args) {
OleDbConnection thisConnection = new
OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=E:\db1.mdb");
OleDbDataAdapter thisAdapter = new OleDbDataAdapter(
"SELECT * FROM Student", thisConnection);
OleDbCommandBuilder thisBuilder = new OleDbCommandBuilder(thisAdapter);
DataSet thisDataSet = new DataSet();
thisAdapter.Fill(thisDataSet, "Stu");
Console.WriteLine("# rows before change: {0}",
thisDataSet.Tables["Stu"].Rows.Count );
DataRow thisRow = thisDataSet.Tables["Stu"].NewRow();
thisRow["姓名"] = "张华";
thisRow["年龄"] = 21;
thisDataSet.Tables["Stu"].Rows.Add(thisRow);
Console.WriteLine("# rows after change: {0}", thisDataSet.Tables["Stu"].Rows.Count);
thisAdapter.Update(thisDataSet, "Stu");
thisConnection.Close();
Console.Write("Program finished, press Enter/Return to continue:");
Console.ReadLine();
}
例:在student表中查找名为“林文”的记录,若不存在则插入;若存在则输出相应信息
static void Main(string[] args)
{
OleDbConnection thisConnection = new OleDbConnection(
@"Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=E:\db1.mdb");
OleDbDataAdapter thisAdapter = new OleDbDataAdapter(
"SELECT * FROM student", thisConnection);
OleDbCommandBuilder thisBuilder = new OleDbCommandBuilder(thisAdapter);
DataSet thisDataSet = new DataSet();
thisAdapter.Fill(thisDataSet, "Stu");
Console.WriteLine("# rows before change: {0}", thisDataSet.Tables["Stu"].Rows.Count);
DataColumn[] keys = new DataColumn[1];
keys[0] = thisDataSet.Tables["Stu"].Columns["姓名"];
thisDataSet.Tables["Stu"].PrimaryKey = keys;
DataRow findRow = thisDataSet.Tables["Stu"].Rows.Find("林文");
if (findRow == null)
{
Console.WriteLine("林文 not found, will add to Stu table");
DataRow thisRow = thisDataSet.Tables["Stu"].NewRow();
thisRow["姓名"] = "林文";
thisRow["年龄"] = 35;
thisRow["性别"] = "男";
thisRow["职业"] = "学生";
thisDataSet.Tables["Stu"].Rows.Add(thisRow);
if ((findRow =thisDataSet.Tables["Stu"].Rows.
Find("林文")) != null) {
Console.WriteLine("林文 successfully added to
Customers table");
}
}
else
{ Console.WriteLine("林文 already present in database"); }
thisAdapter.Update(thisDataSet, "Stu");
Console.WriteLine("# rows after change: {0}",
thisDataSet.Tables["Stu"].Rows.Count);
thisConnection.Close();
Console.Write("Program finished, press Enter/Return to continue:");
Console.ReadLine();
}
例:在student表中查找名为“张华”的记录,若
存在则删除该记录
static void Main(string[] args)
{
OleDbConnection thisConnection = new OleDbConnection(
@"Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=E:\db1.mdb");
OleDbDataAdapter thisAdapter = new OleDbDataAdapter(
"SELECT * FROM student", thisConnection);
OleDbCommandBuilder thisBuilder = new OleDbCommandBuilder(thisAdapter);
DataSet thisDataSet = new DataSet();
thisAdapter.Fill(thisDataSet, "Stu");
Console.WriteLine("# rows before change: {0}", thisDataSet.Tables["Stu"].Rows.Count);
DataColumn[] keys = new DataColumn[1];
keys[0] = thisDataSet.Tables["Stu"].Columns["姓名"];
thisDataSet.Tables["Stu"].PrimaryKey = keys;
DataRow findRow = thisDataSet.Tables["Stu"].Rows.
Find("张华");
if (findRow != null) {
Console.WriteLine("张华 already in Customers table");
Console.WriteLine("Removing 张华 . . .");
findRow.Delete();
thisAdapter.Update(thisDataSet, "Stu");
}
Console.WriteLine("# rows after change: {0}", thisDataSet.Tables["Stu"].Rows.Count);
thisConnection.Close();
Console.Write("Program finished, press Enter/Return to
continue:");
Console.ReadLine();
}
在ADO.NET中访问多个表
DataRelation
DataRelation对象用于描述DataSet中的多个DataTables对象之间的关系
DataRelation custOrderRel=thisDataSet.Relations.
Add(“CustOrders”,thisDataSet.Tables[“Customers”].
Columns[“CustomerID”],thisDataSet.Tables[“Orders”].
Columns[“CustomerID”]);
导航关系
指从一张表的行进入另一张表的关联行
public DataRow[] GetChildRows ( DataRelation )
DataRow类
例:输出每个学生的基本信息及其选课情况
static void Main(string[] args)
{
OleDbConnection thisConnection = new OleDbConnection(
@"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=E:\db1.mdb");
DataSet thisDataSet = new DataSet();
OleDbDataAdapter stuAdapter = new OleDbDataAdapter( "SELECT * FROM student", thisConnection);
OleDbDataAdapter grdAdapter = new OleDbDataAdapter( "SELECT * FROM 选课", thisConnection);
stuAdapter.Fill(thisDataSet, "Stu");
grdAdapter.Fill(thisDataSet, "Grd");
DataRelation stuGrdRel = thisDataSet.Relations.Add("stuGrds",
thisDataSet.Tables["Stu"].Columns["姓名"], thisDataSet.Tables["Grd"].Columns["姓名"]);
foreach (DataRow stuRow in thisDataSet.Tables["Stu"].Rows)
{
Console.WriteLine("姓名: " + stuRow["姓名"] +
" 年龄: " + stuRow["年龄"]+" 性别: "+stuRow["性别"]+
" 职业: "+stuRow["职业"]);
}
foreach (DataRow grdRow in stuRow.GetChildRows(stuGrdRel))
{
Console.WriteLine(" 课程名: " + grdRow["课程名"]+“
成绩: "+grdRow["成绩"]);
}
thisConnection.Close();
Console.Write("Program finished, press Enter/Return to continue:");
Console.ReadLine();
}
处理更多关系
public DataRow GetParentRow ( DataRelation relation )
例:输出每个学生的基本信息及其选课情况和课程信息
static void Main(string[] args)
{
OleDbConnection thisConnection = new OleDbConnection(
@"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=E:\db1.mdb");
DataSet thisDataSet = new DataSet();
OleDbDataAdapter stuAdapter = new OleDbDataAdapter( "SELECT * FROM student", thisConnection);
OleDbDataAdapter grdAdapter = new OleDbDataAdapter("SELECT * FROM 选课", thisConnection);
stuAdapter.Fill(thisDataSet, "Stu");
grdAdapter.Fill(thisDataSet, "Grd");
OleDbDataAdapter crsAdapter = new OleDbDataAdapter( "select * from Course", thisConnection);
crsAdapter.Fill(thisDataSet, "Crs");
DataRelation stuGrdRel = thisDataSet.Relations.Add("stuGrds",
thisDataSet.Tables["Stu"].Columns["姓名"],
thisDataSet.Tables["Grd"].Columns["姓名"]);
DataRelation crsGrdRel = thisDataSet.Relations.Add("crsGrds",
thisDataSet.Tables["Crs"].Columns["课程名"],
thisDataSet.Tables["Grd"].Columns["课程名"]);
foreach (DataRow stuRow in thisDataSet.Tables["Stu"].Rows)
{
Console.WriteLine("姓名: " + stuRow["姓名"] +
" 年龄: " + stuRow["年龄"] + " 性别: " +
stuRow["性别"] + " 职业: " + stuRow["职业"]);
}
foreach (DataRow grdRow in stuRow.GetChildRows(stuGrdRel))
{
Console.WriteLine(" 课程名: " + grdRow["课程名"] +
" 学分: "+grdRow.GetParentRow(crsGrdRel)["学分"]+
" 周学时: "+grdRow.GetParentRow(crsGrdRel)["周学时"]+
" 成绩: " + grdRow["成绩"]);
}
}
thisConnection.Close();
Console.Write("Program finished, press Enter/Return to continue:");
Console.ReadLine();
}
ADO.NET允许在列上创建一组约束,对数据应用一些规则
ForeignKeyConstraint 在DataSet的两个DataTable之间强制连接
UniqueConstraint 确保给定的列是唯一的
设置主键
当把主键添加到DataTable中时,运行库也会对键列生成一个唯一约束
public static void ManufacturePrimaryKey( DataTable dt)
{
DataColumn[] pk=new DataColumn[1];
pk[0]=dt.Columns[“ProductID”];
dt.PrimaryKey=pk;
}
上述代码自动生成的约束是Constraint1, 这个名称没有什么用,因此应避免这种情况,最好先在代码中创建约束,然后定义组成主键的列
DataColumn[] pk=new DataColumn[1];
pk[0]=dt.Columns[“ProductID”];
dt.Constraints.Add(new UniqueConstraint(“PK_Products”,pk[0]);
dt.PrimaryKey=pk;
设置外键
除了唯一约束外,DataTable类还可以包含外键约束,用于强制主/从关系
DataTable categories=new DataTable(“Categories”);
categories.Columns.Add(new DataColumn( “CategoryID”, typeof(int)));
categories.Columns.Add(new DataColumn( “CategoryName”, typeof(string)));
categories.Columns.Add(new DataColumn( “Description”, typeof(string)));
categories.Constraints.Add(new UniqueConstraint (“PK_Categories”, categories.Columns[“CategoryID”]));
categories.PrimaryKey=new DataColumn[1]{ categories.Columns[“CategoryID”]};
DataColumn parent=ds.Tables[“Categories”]. Columns[“CategoryID”];
DataColumn child=ds.Tables[“Products”].Columns [“CategoryID”];
ForeignKeyConstraint fk=new ForeignKeyConstraint (“FK_Product_CategoryID”, parent, child);
fk.UpdateRule=Rule.Cascade;
fk.DeleteRule=Rule.SetNull;
ds.Tables[“Products”].Constraints.Add(fk);
设置更新和删除约束
在对父表中的列(或行)执行某种操作时,使用这些规则,来确定对影响到的子表中的行进行什么操作。通过Rule枚举可应用4种不同的规则:
Cascade—如果更新了父键,就应把新的键值复制到所有子记录中。如果删除了父记录,则也将删除子记录。
None—不执行任何操作,这个选项会留下子数据表中的孤立行
SetDefault—如果定义了一个子记录,那么每个受影响的子记录都把外键列设置为其默认值
SetNull—所有子行都把键列设置为DBNull
ADO.NET中的SQL支持
查看CommandBuilder对象生成的SQL语句
static void Main(string[] args)
{
OleDbConnection thisConnection = new OleDbConnection(
@"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=E:\db1.mdb");
thisConnection.Open();
OleDbDataAdapter thisAdapter = new
OleDbDataAdapter("SELECT 姓名 from student", thisConnection);
OleDbCommandBuilder thisBuilder = new OleDbCommandBuilder(thisAdapter);
Console.WriteLine("SQL SELECT Command is:\n{0}\n", thisAdapter.SelectCommand.CommandText);
OleDbCommand updateCommand = thisBuilder.GetUpdateCommand();
Console.WriteLine("SQL UPDATE Command is:\n{0}\n“, updateCommand.CommandText);
OleDbCommand insertCommand = thisBuilder.GetInsertCommand();
Console.WriteLine("SQL INSERT Command is:\n{0}\n", insertCommand.CommandText);
OleDbCommand deleteCommand = thisBuilder.GetDeleteCommand();
Console.WriteLine("SQL DELETE Command is:\n{0}", deleteCommand.CommandText);
thisConnection.Close();
Console.Write("Program finished, press Enter/Return to continue:");
Console.ReadLine();
}