C# .NET DataTable、DataSet 和 DataGrid 实用指南 - 第三部分






4.82/5 (27投票s)
2004 年 2 月 24 日
5分钟阅读

338061

2
本文档旨在提供使用 Microsoft .NET DataTables、DataSets 和 DataGrid 的实用指南
4 DataSet
4.1 DataSet 方法
| DataSet 方法 | 描述 | 
| 
 | 接受对 DataSet 的所有更改 | 
| 
 | 从 DataSet 中的所有表中删除所有行,即删除所有数据。 | 
| 
 | 创建一个新的 DataSet,其中所有表都具有相同的表结构,包括任何约束和关系。不复制数据。 | 
| 
 | 与 DataSet 的  | 
| 
 | 创建一个包含对 DataSet 所做更改的 DataSet。如果调用了 AcceptChanges,则仅返回自上次调用以来所做的更改。 | 
| 
 | 如果对 DataSet 进行了任何更改(包括添加表和修改行),则返回 true。 | 
| 
 | 输出一个 XML 文件,其中包含所有表、数据、约束和关系的架构。 | 
| 
 | 输入一个包含架构、表、数据、约束和关系的 XML 文件。 | 
4.2 DataSet 属性
| DataSet 属性 | 描述 | ||||||||||||||||||||
| 
 | 如果设置为 true,则 DataSet 表中的字符串比较区分大小写,否则不区分。 | ||||||||||||||||||||
| 
 | DataSet 的名称 | ||||||||||||||||||||
| 
 | 如果在 DataSet 中的任何表中存在错误,则返回 true。 | ||||||||||||||||||||
| 
 | 关系集合 
 | ||||||||||||||||||||
| 
 | 表集合 
 | 
4.3 加载 DataSet
4.3.1 从表加载
如“表”部分所述创建并填充数据的表,可以使用 Add() 方法添加到 Tables 集合中,或者可以使用 AddRange() 方法一次性添加。
使用 Add() 和 AddRange() 将表 dtElements 和 dtIsotopes 添加到 DataSet ElementDS 的两个等效方法示例。
方法 1 – Tables.Add()
// Add the Elements table to the DataSet
elementDS.Tables.Add(dtElements);
// Add the Isotopes table to the DataSet
elementDS.Tables.Add(dtIsotopes);
方法 2 – Tables.AddRange()
ElementDS.Tables.AddRange(new DataTable()
{dtElements, dtIsotopes});
4.3.2 从数据库加载
DataSet 的表集合还可以填充包含数据库记录集数据的关联表,这些数据被视为绑定数据。
4.3.2.1 方法 1 – SqlDataAdapter
以下代码说明了如何使用 SqlDataAdapter 的 Fill() 方法直接加载或绑定数据库记录集,其中 select 查询字符串用于创建记录集。调用 Fill() 方法后,ds 将在其集合中包含一个表,其列标题与 select 查询字符串中的字段名称匹配,列数据类型将与数据库表元素中指定的匹配。每一行都包含对应于每个字段的数据。
System.Data.SqlClient.SqlConnection sqlConnection1;
System.Data.SqlClient.SqlDataAdapter sqlDataAdapter1;
System.Data.SqlClient.SqlCommand sqlSelectCommand1;
sqlConnection1 = new System.Data.SqlClient.SqlConnection();
sqlDataAdapter1 = new System.Data.SqlClient.SqlDataAdapter();
sqlSelectCommand1 = new System.Data.SqlClient.SqlCommand();
sqlSelectCommand1.CommandText = "SELECT ElementsID, AtomicNbr,”
+ “Symbol, AtomicMass, Element FROM [Elements]";
sqlDataAdapter1.SelectCommand = sqlSelectCommand1;
//
// sqlConnection1
// <replace xxxxx, nnnnn and dbName with appropriate values>
//
sqlConnection1.ConnectionString = “workstation id=xxxxx;packet “
+ “ size=4096;user id=nnnnn; pwd=yyyyy;data “
+ “ source=xxxxx; persist”
+ “ security info=False; initial catalog=dbName”;
sqlSelectCommand1.Connection = sqlConnection1;
DataSet ds = new DataSet();
sqlDataAdapter1.Fill(ds);
4.3.2.2 方法 2 – SqlDataReader
此方法比使用 SqlDataAdapter 的 Fill() 方法复杂,但它允许在填充表行之前对数据进行预处理,并且数据不直接绑定到数据库。在此示例中,为了说明目的,不是通过 SQL 查询将数据库记录集限制为包含不同的原子序数行,而是以编程方式完成。
string SQL= "SELECT ElementsID, AtomicNbr, " +
"Symbol, AtomicMass, Element”
+ “ FROM [Elements] order by AtomicNbr ASC";
sqlConnection sqlConnection1=
new sqlConnection (
 "connection info to MSDE or SQL Server 2000+”;);
sqlCommand sqlCommand = new sqlCommand (SQL,sqlConnection1);
sqlConnection1.Open();
sqlDataReader elementReader = SqlCommand.ExecuteReader();
// Starting with the element table dt defined in
// the Tables section, an ElementID column
// is added that will be used as the primary key for the row.
DataColumn dc = new DataColumn(“ElementsID”,
 System.Type.GetType(“System.Guid”));
dt.Columns.Add(dc);
// Make ‘ElementsID’ a primary key:
dt.PrimaryKey = new DataColumn[]{dt.Columns["ElementsID"]};
// Fill table dt with data from the database table Elements:
注意: SqlDataReader 类有一个方法可以用来确定为特定单元格返回的是 null 值还是不存在的值。例如:
If (!elementReader.IsDBNull(elementReader.GetOrdinal("AtomicNbr")))
{
   // fill cell with value
}
else
{
   // handle this condition
   // for example fill cell with a default value
}
为简洁起见,以下代码中省略了此检查,但使用它是一种好习惯。
DataRow dr;
int PrevAtomicNbr = 0;
try
{
  while(myReader.Read())
  {
  if (PrevAtomicNbr != elementReader.GetInt32(
    elementReader.GetOrdinal("AtomicNbr")))
  {
  PrevAtomicNbr = elementReader.GetInt32(
    elementReader.GetOrdinal("AtomicNbr"));
  dr = dt.NewRow();
  dr[“ElementsID”] =
  elementReader.GetGuid(elementReader.GetOrdinal("ElementsID"));
  dr[“AtomicNbr”] = elementReader.GetInt32(
    elementReader.GetOrdinal("AtomicNbr"));
  dr[“Symbol”] = elementReader.GetString(
    elementReader.GetOrdinal("Symbol));
  dr[“Element”] = elementReader.GetString(
    elementReader.GetOrdinal("Element"));
  dr[“AtomicMass”] =
    elementReader.GetDecimal(elementReader.GetOrdinal("AtomicMass"));
  dt.Rows.Add(dr);
  }
 }
}
finally
{
  elementReader.Close();
  sqlConnection1.Close();
}
dt.AcceptChanges();
// Add table dt to a new dataset ds and its tables collection
DataSet ds = new DataSet();
ds.Tables.Add(dt);
4.4 关联表
此示例演示了如何通过主键将两个表关联起来。在此示例中,创建了一个 TableName 为 Elements 的表,其主键为“Atomic Number”。第二个 TableName 为 Isotopes 的表通过关系链接,将其 Atomic Number 列与 Elements 主键关联。
// create a new DataSet named Periodic that will
// hold two linked tables with
// TableNames of Elements and Isotopes respectively.
DataSet elementDS = new DataSet("Periodic");
// Create Elements Table
DataTable dtElements = new DataTable("Elements");
dtElements.Columns.Add("Atomic Number", typeof(int));
dtElements.Columns.Add("Element", typeof(string));
dtElements.Columns.Add("Symbol", typeof(string));
// Make ‘Atomic Number’ a primary key in Elements table
dtElements.PrimaryKey = new DataColumn[]
{dtElements.Columns["Atomic Number"]};
// Create Isotopes Table
DataTable dtIsotopes = new DataTable("Isotopes");
dtIsotopes.Columns.Add("Symbol", typeof(string));
dtIsotopes.Columns.Add("Atomic Number", typeof(int));
dtIsotopes.Columns.Add("Isotope Number",typeof(int));
dtIsotopes.Columns.Add("Percent Abundance",
typeof(System.Decimal))
dtIsotopes.Columns.Add("Atomic Mass", typeof(System.Decimal));
// Add tables to the Dataset
ElementDS.Tables.AddRange(new DataTable(){dtElements, dtIsotopes});
DataSet.Relations.Add()
// Add a relationship for Tables Elements and Isotopes
// through the primary key ‘Atomic Number’ in DataSet
// Periodic and name the relationship ‘Isotopes’. This name is
// used in the DataGrid to select table rows, in table Isotopes,
// that contain isotope values for the selected element.
elementDS.Relations.Add("Isotopes",
elementDS.Tables["Elements"].Columns["Atomic Number"],
elementDS.Tables["Isotopes"].Columns["Atomic Number"] );
4.5 DataSet 中的关联表
4.5.1 填充
假设存在另一个 DataSet ds,其 Tables 集合中有一个索引为 0 的表,该表包含 Element 和 Isotope 数据,将用于填充前面部分定义的 elementDS DataSet 表集合中包含的关联表。假设 DataSet ds 中的 Table[0] 具有以下列:
AtomicNbr、Element、Symbol、IsotopeNbr、PctAbundance 和 AtomicMass
其中行按原子序数升序排序,然后按同位素编号升序排序。
// Assign the table containing both Elements and
// Isotopes to dt using index 0
DataTable dt = ds.Tables[0];
// Create two DataTable variables dtElements and dtIsotopes and
// assign tables contained in the DataSet elementDS Tables
// collection using TableNames as indexes.
DataTable dtElements = elementDS.Tables[“Elements”];
DataTable dtIsotopes = elementDS.Tables[“Isotopes”];
DataRow drElement;
DataRow drIsotope;
int prevAtomicNbr = 0;
foreach (DataRow dr in dt.Rows)
{
  if(prevAtomicNbr != (int)dr["AtomicNbr"])
    { //need only one row per AtomicNbr in Table[“Elements”]
      // Fill an element row with data from dt.
     prevAtomicNbr = (int)dr["AtomicNbr"];
     drElement = dtElements.NewRow();
     drElement["Atomic Number"] = dr["AtomicNbr"];
     drElement["Element"] = dr["Element"];
     drElement["Symbol"] = dr["Symbol"];
     dtElements.Rows.Add(drElement);
   }
  // Fill an isotope row with data from dt.
  drIsotope = dtIsotopes.NewRow();
  drIsotope["Isotope Number"] = dr["IsotopeNbr"];
  drIsotope["Symbol"] = dr["Symbol"];
  drIsotope["Atomic Number"] = dr["AtomicNbr"];
  drIsotope["Percent Abundance"] = dr["PctAbundance"];
  drIsotope["Atomic Mass"] = dr["AtomicMass"];
  dtIsotopes.Rows.Add(drIsotope);
}
4.5.2 删除
要从 DataSet 中删除所有关联表或选定的关联表,首先必须删除所有关系,然后是约束,最后是表,否则会生成关系/约束表错误。
以下代码示例提供了一个通用的例程,用于删除数据集中所有关联的表。
public void RemoveAllTables(DataSet ds)
{
  // need to do it in reverse order due to constraints
  ds.Relations.Clear();
  for (int i=ds.Tables.Count -1; i >=0; i--)
  {
   ds.Tables[i].Constraints.Clear();
   ds.Tables.RemoveAt(i);
  }
} 
4.6 XML 导出和导入 DataSet 数据
4.6.1 WriteXml
通过指定 DataSet 的属性 Namespace 并使用 WriteXml 方法,可以将 DataSet 中包含的所有表及其架构、关系、约束和数据导出为 XML。
例如
ds.Namespace = "http://www.mydomain.com/xmlfiles”
ds.WriteXml(FileName, XmlWriteMode.WriteSchema);
4.6.2 ReadXml
通过指定 DataSet 的属性 Namespace 并使用 ReadXml 方法,将 XML 文件中包含的所有表及其架构、关系、约束和数据导入到 DataSet 中。一旦进入 DataSet,它就与其他任何数据集一样。
例如
DataSet ds = new DataSet();
ds.Namespace = "http://www.mydomain.com/xmlfiles";
ds.ReadXml(FileName, XmlReadMode.ReadSchema);
4.7 处理 DataSet 错误
与 DataTable 的 HasErrors 属性类似,DataSet 的 HasErrors 属性会在 DataSet 管理的任何表中发生错误时返回 true。
if(ds.HasErrors)
{ // One or more of the tables in the DataSet has errors.
  MessageBox.Show("DataSet has Errors");
  // Insert code to resolve errors.
  // Refer to ‘Handling DataTable Errors’ section for example of
  // handling errors within tables.
}
4.8 使用 DataSet/DataTable 更改更新数据库
以下代码显示了如何创建包含 DataSet 中表的已发生更改的 DataSet。新 DataSet 可用于更新数据库。
// Create temporary DataSet variable.
DataSet dsChanges;
// GetChanges for modified rows only.
dsChanges = ds.GetChanges(DataRowState.Modified);
// Check the DataSet for errors.
if(!dsChanges.HasErrors)
{
  // No errors were found, update the DBMS with the SqlDataAdapter da
  // used to create the DataSet.
  da.RowUpdating += new SqlRowUpdatingEventHandler(OnRowUpdating);
  da.RowUpdated += new SqlRowUpdatedEventHandler(OnRowUpdated);
  int res = da.Update(dsChanges); // returns the number of rows updated
  da.RowUpdating -= new SqlRowUpdatingEventHandler(OnRowUpdating);
  da.RowUpdated -= new SqlRowUpdatedEventHandler(OnRowUpdated);
}
