浅学C#(27)——数据库

ADO.NET概述

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支持外键约束和唯一键约束

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)
 {
    ……
 }
处理Connection对象的事件

StateChange事件发生在Connection对象状态改变后,传递一个StateChangeEventArgs对象给它的处理程序
StateChangeEventArgs对象有两个属性:OriginalState和CurrentState

  • Connection对象的状态值
    Broken 连接已打开但不起作用,需要关闭后重新打开
    Closed 连接已关闭
    Connecting 正在连接中,但尚未打开
    Executing 连接正在执行一个命令
    Fetching 连接正在检索数据
    Open 连接已打开
事务处理
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与DataReader

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对象

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();
}

      

你可能感兴趣的:(浅学C#)