C# DataSet和DataTable详解

在项目中经常用到DataTable,如果DataTable使用得当,不仅能使程序简洁实用,而且能够提高性能,达到事半功倍的效果,现对DataTable的使用技巧进行一下总结。

一、DataTable简介

(1)构造函数

DataTable() 不带参数初始化DataTable 类的新实例。

DataTable(string tableName) 用指定的表名初始化DataTable 类的新实例。

DataTable(string tableName, string tableNamespace) 用指定的表名和命名空间初始化DataTable 类的新实例。

(2) 常用属性

CaseSensitive 指示表中的字符串比较是否区分大小写。

ChildRelations 获取此DataTable 的子关系的集合。

Columns 获取属于该表的列的集合。

Constraints 获取由该表维护的约束的集合。

DataSet 获取此表所属的DataSet。DataSet相关信息,可见我以前的一篇文章《数据访问(2)-DataSet》

DefaultView 获取可能包括筛选视图或游标位置的表的自定义视图。

HasErrors 获取一个值,该值指示该表所属的DataSet 的任何表的任何行中是否有错误。

MinimumCapacity 获取或设置该表最初的起始大小。该表中行的最初起始大小。默认值为 50。

Rows 获取属于该表的行的集合。

TableName 获取或设置DataTable 的名称。

(3)常用方法

AcceptChanges() 提交自上次调用AcceptChanges() 以来对该表进行的所有更改。

BeginInit() 开始初始化在窗体上使用或由另一个组件使用的DataTable。初始化发生在运行时。

Clear() 清除所有数据的DataTable。

Clone() 克隆DataTable 的结构,包括所有DataTable 架构和约束。

EndInit() 结束在窗体上使用或由另一个组件使用的DataTable 的初始化。初始化发生在运行时。

ImportRow(DataRow row) 将DataRow 复制到DataTable 中,保留任何属性设置以及初始值和当前值。

Merge(DataTable table) 将指定的DataTable 与当前的DataTable 合并。

NewRow() 创建与该表具有相同架构的新DataRow。

二、DataTable使用技巧

(1)Create a DataTable

DataTable dt = new DataTable("Table_AX");

(2)Add columns for DataTable

//Method 1

dt.Columns.Add("column0", System.Type.GetType("System.String"));

//Method 2

DataColumn dc = new DataColumn("column1", System.Type.GetType("System.Boolean"));

dt.Columns.Add(dc);

(3)Add rows for DataTable

//Initialize the row

DataRow dr = dt.NewRow();

dr["column0"] = "AX";

dr["column1"] = true;

dt.Rows.Add(dr);

//Doesn't initialize the row

DataRow dr1 = dt.NewRow();

dt.Rows.Add(dr1);

(4)Select row

//Search the second row 如果没有赋值,则用is null来select

DataRow[] drs = dt.Select("column1 is null");

DataRow[] drss = dt.Select("column0 = 'AX'");

(5)Copy DataTable include data

DataTable dtNew = dt.Copy();

(6)Copy DataTable only scheme

DataTable dtOnlyScheme = dt.Clone();

(7)Operate one row

//对dt的操作

//Method 1

DataRow drOperate = dt.Rows[0];

drOperate["column0"] = "AXzhz";

drOperate["column1"] = false;

//Method 2

drOperate[0] = "AXzhz";

drOperate[1] = false;

//Method 3

dt.Rows[0]["column0"] = "AXzhz";

dt.Rows[0]["column1"] = false;

//Method 4

dt.Rows[0][0] = "AXzhz";

dt.Rows[0][1] = false;

(8)Evaluate another DataTable's row to current Datatable

dtOnlyScheme.Rows.Add(dt.Rows[0].ItemArray);

(9)Convert to string

System.IO.StringWriter sw = new System.IO.StringWriter();

System.Xml.XmlTextWriter xw = new System.Xml.XmlTextWriter(sw);

dt.WriteXml(xw);

string s = sw.ToString();

(10)Filter DataTable

dt.DefaultView.RowFilter = "column1 <> true";

dt.DefaultView.RowFilter = "column1 = true";

(11)Sort row

dt.DefaultView.Sort = "ID ,Name ASC";

dt=dt.DefaultView.ToTable();

(12)Bind DataTable

//绑定的其实是DefaultView

gvTestDataTable.DataSource = dt;

gvTestDataTable.DataBind();

(13)judge the DataTable’s Column name is a string

//判断一个字符串是否为DataTable的列名

dtInfo.Columns.Contains("AX");

(14)DataTable convert to XML and XML convert to DataTable

protected void Page_Load(object sender, EventArgs e)

{

DataTable dt_AX = new DataTable();

//dt_AX.Columns.Add("Sex", typeof(System.Boolean));

//DataRow dr = dt_AX.NewRow();

//dr["Sex"] = true;

//dt_AX.Rows.Add(dr);

string xml=ConvertBetweenDataTableAndXML_AX(dt_AX);

DataTable dt = ConvertBetweenDataTableAndXML_AX(xml);

}

public string ConvertBetweenDataTableAndXML_AX(DataTable dtNeedCoveret)

{

System.IO.TextWriter tw = new System.IO.StringWriter();

//if TableName is empty, WriteXml() will throw Exception.

dtNeedCoveret.TableName=dtNeedCoveret.TableName.Length==0?"Table_AX":dtNeedCoveret.TableName;

dtNeedCoveret.WriteXml(tw);

dtNeedCoveret.WriteXmlSchema(tw);

return tw.ToString();

}

public DataTable ConvertBetweenDataTableAndXML_AX(string xml)

{

System.IO.TextReader trDataTable = new System.IO.StringReader(xml.Substring(0, xml.IndexOf("<?xml")));

System.IO.TextReader trSchema = new System.IO.StringReader(xml.Substring(xml.IndexOf("<?xml")));

DataTable dtReturn = new DataTable();

dtReturn.ReadXmlSchema(trSchema);

dtReturn.ReadXml(trDataTable);

return dtReturn;

}

===========================================================================

1、创建DataSet对象:

  DataSet ds = new DataSet("DataSetName");

  2、查看调用SqlDataAdapter.Fill创建的结构

  da.Fill(ds,"Orders");

  DataTable tbl = ds.Table[0];

  foreach(DataColumn col in tbl.Columns)

  Console.WriteLine(col.ColumnName);

  3、查看SqlDataAdapter返回的数据

  ①、DataRow对象

  DataTable tbl = ds.Table[0];

  DataRow row = tbl.Row[0];

  Console.WriteLine(ros["OrderID"]);

  ②、检查存储在DataRow中的数据

  DataTable tbl = row.Table;

  foreach(DataColumn col in tbl.Columns)

  Console.WriteLine(row[col]);

  ③、检查DatTable中的DataRow对象

  foreach(DataRow row in tbl.Rows)

  DisplayRow(row);

  4、校验DataSet中的数据

  ①、校验DataColumn的属性:ReadOnly,AllowDBNull,MaxLength,Unique

  ②、DataTable对象的Constrains集合:UiqueConstraints,Primarykey,ForeignkeyConstraints

  通常不必刻意去创建ForeignkeyConstraints,因为当在DataSet的两个DataTable对象之间创建关系时会创建一个。

  ③、用SqlDataAdapter.Fill模式来检索模式信息

  5、编写代码创建DataTable对象

  ①、创建DataTable对象:DataTable tbl = new DataTable("TableName");

  ②、将DataTable添加到DataSet对象的Table集合

  DataSet ds = new DataSet();

  DataTable tbl = new DataTable("Customers");

  ds.Tables.Add(tbl);

  DataSet ds = new DataSet();

  DataTable tbl = ds.Tables.Add("Customers");

  DataTable对象只能存在于至多一个DataSet对象中。如果希望将DataTable添加到多个DataSet中,就必须使用Copy方法或Clone方法。Copy方法创建一个与原DataTable结构相同并且包含相同行的新DataTable;Clone方法创建一个与原DataTable结构相同,但没有包含任何行的新DataTable。

  ③、为DataTable添加列

  DataTable tbl = ds.Tables.Add("Orders");

  DataColumn col =tbl.Columns.Add("OrderID",typeof(int));

  col.AllowDBNull = false;

  col.MaxLength = 5;

  col.Unique = true;

  tbl.PrimaryKey = new DataColumn[]{tbl.Columns["CustomersID"]};

  当设置主键时,AllowDBNull自动设置为False;

  ④、处理自动增量列

  DataSet ds = new DataSet();

  DataTable tbl = ds.Tables.Add("Orders");

  DataColumn col = tbl.Columns.Add("OrderID",typeof(int));

  col.AutoIncrement = true;

  col.AutoIncrementSeed = -1;

  col.AutoIncrementStep = -1;

  col.ReadOnly = true;

  ⑤、添加基于表达式的列

  tbl.Columns.Add("ItemTotal",typeof(Decimal),"Quantity*UnitPrice");

  6、修改DataTable内容

  ①、添加新DataRow

  DataRow row = ds.Tables["Customers"].NewRow();

  row["CustomerID"] = "ALFKI";

  ds.Tables["Customers"].Rows.Add(row);

  object[] aValues ={"ALFKI","Alfreds","Anders","030-22222"};

  da.Tables["Customers"].LoadDataRow(aValues,false);

  ②、修改当前行

  修改行的内容逼供内不会自动修改数据库中相应的内容,对行所做的修改被视为是随后将使用SqlDataAdapter对象来提交交给数据库的待定的更改。

  DataRow rowCustomer;

  rowCustomer = ds.Tables["Custoemrs"].Rows.Find("ANTON");

  if(rowCustomer == null)

  //没有查找客户

  else

  {

  rowCustomer["CompanyName"] ="NewCompanyName";

  rowCustomer["ContactName"] ="NewContactName";

  }

  //推荐使用这种方式

  DataRow rowCustomer;

  rowCustomer = ds.Tables["Custoemrs"].Rows.Find("ANTON");

  if(rowCustomer == null)

  //没有查找客户

  else

  {

  rowCustomer.BeginEdit();

  rowCustomer["CompanyName"] ="NewCompanyName";

  rowCustomer["ContactName"] ="NewContactName";

  rowCustomer.EndEdit();

  }

  //null表示不修改该列的数据

  obejct[] aCustomer ={null,"NewCompanyName","NewContactName",null}

  DataRow rowCustomer;

  rowCustomer = ds.Tables["Customers"].Rows.Find("ALFKI");

  rowCustomer.ItemArray = aCustomer;

  ③、处理DataRow的空值

  //查看是否为空

  DataRow rowCustomer;

  rowCustomer = ds.Tables["Customers"].Rows.Find("ALFKI");

  if(rowCustomer.IsNull("Phone"))

  Console.WriteLine("It's Null");

  else

  Console.WriteLine("It's not Null");

  //赋予空值

  rowCustomer["Phone"] = DBNull.Value;

  ④、删除DataRow

  DataRow rowCustomer;

  rowCustomer = ds.Tables["Customers"].Rows.Find("ALFKI");

  rowCustomer.Delete();

  ⑤、清除DataRow

  DataRow rowCustomer = ds.Tables["Customers"].Rows.Find("ALFKI");

  rowCustomer.ItemArray = aCustomer;

  da.Tables["Customers"].Remove(rowCustomer);

  或者

  ds.Tables["Customers"].RemoveAt(intIndex);

  ⑥、使用DataRow.RowState属性 :Unchanged,Detached,Added,Modified,Deleted

  private void DemonstrateRowState()

  { // Run a function to create a DataTable with one column. DataTable myTable = MakeTable();DataRow myRow;

  // Create a new DataRow. myRow = myTable.NewRow();// Detached row. Console.WriteLine("New Row " + myRow.RowState);

  myTable.Rows.Add(myRow);// New row. Console.WriteLine("AddRow " + myRow.RowState);

  myTable.AcceptChanges();// Unchanged row. Console.WriteLine("AcceptChanges " + myRow.RowState);

  myRow["FirstName"] = "Scott";// Modified row. Console.WriteLine("Modified " + myRow.RowState);

  myRow.Delete();// Deleted row. Console.WriteLine("Deleted " + myRow.RowState);}

  ⑦、检查DataRow中的挂起更改

  DataRow rowCustomer;

  rowCustomer = ds.Tables["Customers"].Rows.Find("ALFKI");

  rowCustomer["CompanyName"] = "NewCompanyName";

  string strNewCompanyName,strOldCompanyName;

  Console.WriteLine(rowCustomer["CompanyName",DataRowVersion.Current]);

  Console.WriteLine(rowCustomer["CompanyName",DataRowVersion.Original]);

  1、DataSet

  ①、属性

  CaseSensitive:用于控制DataTable中的字符串比较是否区分大小写。

  DataSetName:当前DataSet的名称。如果不指定,则该属性值设置为"NewDataSet".如果将DataSet内容写入XML文件,DataSetName是XML文件的根节点名称。

  DesignMode:如果在设计时使用组件中的DataSet,DesignMode返回True,否则返回False.

  HasErrors:表示DataSet中的DataRow对象是否包含错误。如果将一批更改提交给数据库并将DataAdapter对象的ContinueUpdateOnError属性设置为True,则在提交更改后必须检查DataSet的HasErrors属性,以确定是否有更新失败。

  NameSpace和Prefix:指定XML命名空间和前缀

  Relations:返回一个DataRelationCollection对象。

  Tables:检查现有的DataTable对象。通过索引访问DataTable有更好的性能。

  ②、方法

  AcceptChanges和RejectChanges:接受或放弃DataSet中所有挂起更改。调用AcceptChanges时,RowState属性值为Added或Modified的所有行的RowState属性都将被设置为UnChanged.任何标记为Deleted的DataRow对象将从DataSet中删除。调用RejectChanges时,任何标记为Added的DataRow对象将会被从DataSet中删除,其他修改过的DatRow对象将返回前一状态。

  Clear:清除DataSet中所有DataRow对象。该方法比释放一个DataSet然后再创建一个相同结构的新DataSet要快。

  Clone和Copy:使用Copy方法会创建与原DataSet具有相同结构和相同行的新DataSet.使用Clone方法会创建具有相同结构的新DataSet,但不包含任何行。

  GetChanges:返回与原DataSet对象具有相同结构的新DataSet,并且还包含原DataSet中所有挂起更改的行。

  GetXml和GetXmlSchema:使用GetXml方法得到由DataSet的内容与她的架构信息转换为XML格式后的字符串。如果只希望返回架构信息,可以使用GetXmlSchema.

  HasChange:表示DataSet中是否包含挂起更改的DataRow对象。

  Merge:从另一个DataSet、DataTable或现有DataSet中的一组DataRow对象载入数据。

  ReadXml和WriteXml:使用ReadXml方法从文件、TextReader、数据流或者XmlReader中将XML数据载入DataSet中。

  Reset:将DataSet返回为未初始化状态。如果想放弃现有DataSet并且开始处理新的DataSet,使用Reset方法比创建一个DataSet的新实例好。

  ③、事件

  MergeFailed:在DataSet的Merge方法发生一个异常时触发。

  2、DataTable

  ①、属性

  ②、方法

  ③、事件

  ColumnChanged:在列的内容被改变之后触发

  ColumnChangding:在列的内容被改变之前触发

  RowChanged,RowChanging,RowDeleted,RowDeleting.

  3、DataColumn

  ①、属性

  4、DataRow

  ①、属性

  HasError:确定行是否包含错误。

  Item:通过指定行的列数,列的名称或DataColumn对象本身,访问列的内容。

  ItemArray:获取或设置行中所有列的值。

  RowError:返回一个包含行错误信息的字符串。

  RowState:返回DataRowState枚举中的值来表示行的当前状态。

  Table:返回DataRow对象所在的DataTable.

  ②、方法

  AcceptChanges和RejectChanges:提交和放弃挂起更改。

  BeginEdit、CancelEdit、EndEdit

  ClearErrors:清除DataRow中所有的错误。

  Delete:Delete方法实际上并不从DataRow表的Row集合中删除该DataRow.当调用DataRow对象的Delete方法时,ADO.NET将该行标记为删除,之后调用SqlDataAdapter对象的Update方法来删除其在数据库中对应的行。

  如果希望彻底删除DataRow,可以调用Delete方法,接着再调用它的AccepteChanges方法,还可以使用DataRowCollection对象的Remove方法完成相同的任务。

  3 如何遍历DataSet

  foreach(DataTable dt in dataSet.Tables)

  foreach(DataRow dr in dt.Rows)

  foreach(DataColumn dc in dr.Table.Columns)

  Console.WriteLine(dr[dc]);

  浅谈DataSet 的用法

  DataSet是ADO.NET开发人员为方便数据处理开发出来的,是数据的集合,是为解决DataReader的缺陷设计的,DataReader数据处理速度快,但它是只读的, 而且一旦移到下一行,就不能查看上一行的数据,DataSet则可以自由移动指针。DataSet的数据是与数据库断开的。DataSet还可用于多层应用程序中,如果应用程序运行在中间层的业务对象中来访问数据库,则业务对象需将脱机数据结构传递给客户应用程序。

  DataSet的功能:浏览、排序、搜索、过滤、处理分级数据、缓存更改等。还可以与XML数据互换。DataSet中可包括多个DataTable,可将多个查询结构存到一个DataSet中,方便操作,而DataTable中又包括多个DataRow、DataColumn,可通过这些DataRow、DataColumn来查看、操作其中的数据,而需将操作结果返回给数据库的话,则可以调用DataAdapter的Update方法。

  DataSet的操作:

  DataSet ds=new DataSet();

  DataTable dt=new DataTable("newTable");

  ds.Tables.Add(dt);

  DataSet ds=new DataSet();

  DataTable dt=ds.Tables.Add("newTable");

  上述两种方法都可以在DataSet中添加一个DataTable,看需要而进行选择。添加DataTable后,需向其中添加行和列。

  DataSet ds=new DataSet();

  DataTable dt=ds.Tables.Add("newTables");

  DataColumn col=dt.Columns.Add("newColumn",typeof(int));

  col.AllowDBNull=false;

  col.MaxLength=4;

  col.Unique=true;

  上述代码向DataSet中的DataTable中添加名为”newColumn”,类型为int且不为空,最大长度为4和唯一性为真的列。

  dt.PrimaryKey=new DataColumn[]{dt.Columns["ID"]}

  这段代码是继续上面代码的,为一个DataTable中添加一个主键列,主键列是一个数据组,如有多个主键,只需在数组中添加一个列即可。如下:

  dt.PrimaryKey=new DataColumns[]{dt.Columns["OrderID"],dt.Columns["ProductID"]}

  添加外键:

  ForeignKeyConstraint fk;

  fk=new ForeignKeyConstraint(ds.Tables["Customers"].Columns["CustomerID"],ds.Tables["Orders"].Columns["CustomerID"]);

  ds.Tables["Orders"].Constraints.Add(fk);

  //上述代码假如已经为Cusomers表和Orders创建了主键,

此句为添加外键约束。

上述是根据Customers表和Orders表的CustomerID来创建约束。

下面介绍修改DataRow中的内容:

DataRow dr=ds.Tables["Customer"].Rows.Find("ANTON");

if(dr==null)

else

{

dr.BeginEdit();

dr["CompanyName"]="newValue";

dr["ContactName"]="newValue2";

dr.EndEdit();

}

//上面代码通过Row集合的Find方法来在DataTable中的行进行定位,找到"ANTON"行,再修改"ANTON"行中CompanyName列和ContactName列的值。通过BeginEdit和EndEdit来缓存对行的修改,还可调用 CancelEdit为取消修改。

判断某列是否为空值:

DataRow dr=ds.Tables["Customers"].Rows.Find("aaa");

if(dr.IsNull("ContactName");

..

else

dr["ContactName"]=DBNull.Value

//这里判断ContactName列是否为空,如果不是则为其赋空值,呵,很无厘头的做法,这里只为演示为列赋空值的做法。

删除DataRow:

有两种方法可以删除DataRow,Delete方法和Remove方法和RemoveAt方法。其区别是Delete方法实际上不是从DataTable中删除掉一行,而是将其标志为删除,仅仅是做个记号,而Remove方法则是真正的从DataRow中删除一行,RemoveAt方法是根本行的索引来删除。列:

DataRow dr=ds.Tables["table"].Rows.Find("a");

ds.Tables["table"].Remove(dr);

ds.Tables["table"].Remove(index);

//dr 为"a"所在的行,查出后将其删除,index为 "a"所在的索引号。关于DataSet中的其用法,参照MSDN

DataRow dr=ds.Tables["Customers"].Rows.Find("aaa");

if(dr.IsNull("ContactName");

..

else

dr["ContactName"]=DBNull.Value

//这里判断ContactName列是否为空,如果不是则为其赋空值,呵,很无厘头的做法,这里只为演示为列赋空值的做法。

using System.Data;

using System;

using System.Windows.Forms;

class DataT{

static DataTable dt;// = new DataTable();

static DataSet ds;

static void method1(){

dt = new DataTable("Name");

ds = new DataSet();

dt.Columns.Add(new DataColumn("ID", typeof(Int32)));

dt.Columns.Add(new DataColumn("Name", typeof(string)));

dt.Columns.Add(new DataColumn("Sex", typeof(string)));

dt.Columns.Add(new DataColumn("Addr", typeof(string)));

}

static void add(int id,string name,string sex,string addr){

DataRow dr = dt.NewRow();

dr["id"] = id;

dr["Name"] = name;

dr["Sex"] = sex;

dr["Addr"] = addr;

dt.Rows.Add(dr);

}

static void Main(){

DataT DT = new DataT();

method1();

add(100,"Join","Male","北京");

add(101,"Lily","feMale","北京");

add(102,"JIM","Male","北京");

ds.Tables.Add(dt);

foreach(DataRow dr in dt.Rows){

//MessageBox.Show(dr["ID"].ToString() + " " + dr["Name"].ToString() + " " + dr["Sex"].ToString() + " " +

// dr["Addr"].ToString(),"Message");

Console.WriteLine(dr["ID"].ToString() + " " + dr["Name"].ToString() + " " + dr["Sex"].ToString() + " " +

dr["Addr"].ToString());

}

try{

foreach(DataTable dt2 in ds.Tables)

foreach(DataRow dr in dt2.Rows)

Console.WriteLine(dr["ID"].ToString() + " " + dr["Name"].ToString() + " " + dr["Sex"].ToString() + " " +

dr["Addr"].ToString());

}catch(Exception ex){

Console.WriteLine("dkfjksdjfk");

}

}

}