DataTable

来源:互联网 发布:机械动画制作软件 编辑:程序博客网 时间:2024/05/16 16:08

datatabel .net 2.0中变得更加强大,写这篇文章时我觉得有个问题很难决定,我是把它放在ado.net 中还是发在asp.net中,毕竟我经常在asp.net 中使用datatable对象,但是datatabledataset 非常的紧密,最终决定放在ado.net中,正好手中有本讲ado.net的书,我会把读书的心得拿出来和大家分享。

一。创建一个内存表,下面的代码会用到它
DataTable   auto = new DataTable();

auto.Columns.Add("ID");

auto.Columns.Add("Name");

for(int i=1;i<=10;i++)

{

      auto.Rows.Add(new object[]{i,"baibaoqing"});

}

二。下面介绍DataTable对象经常使用的方法

       1. DataTable 的复制和克隆

        创建DataTable的完全副本(full copu 复制表的结构和数据),通过DataTableCopy方法实现

        DataTable copy_Table=auto.Copy()

        for(int i=0;i<copy_Table.Rows.Length;i++)

        {

               Response.Write("<script>alert("+copy_Table.Rows[i][0]+");</script>");

        }

输出的结果为从010 的数字

       有时需要复制DataTable 的表模式(表结果)而不复制数据,可以使用DataTableClone方法

        DataTable clone_Table=auto.Clone();

       在克隆了一个DataTable后,可能需要DataTable对象中的某些DataRow对象(行数据)复制到克隆的DataTabel 中,可以使用DataTable ImPortRow方法

       clone_Table.ImportRow(auto.Rows[0]);

      2.枚举DataTable

      通过Foreach循环遍历DataTable的行和列

      System.Text.StringBuilder   buffer=new System.Text.StringBuiler();

      foreach(DataColumn dc in auto.Colmns)

     {

              buffer.Append(String.Format“{015}”dc.ColumnName);

     }

      buffer.Append("/r/t");

     foreach(DataRow dr in auto.Rows)

     {

             foreach(DataColumn dc in auto.Colmns)

            {

             buffer.Append(String.Format("{0,15}",dr[dc]));  
            }

            buffer.Append("/r/t");

}

textbox1.Text=buffer.ToString();

. 使用DataView

       1. Sort排序

          DataView view=new DataView(auto);

          view.Sort="Make ASC,Year DESC";

          不过我很少使用DataView 的排序功能,我的作法是在SQL语句中使用Order by

        2. 使用RowFilter 精确查找

            DataView view=new DataView(auto);

            view.RowFilter="Make like 'AA%' and Year>2001";

           同样也可以在SQL语句中设置查询条件,看个人的习惯和实际的需要了。

         3 DataView 导出到一个新表

          DataTable new_Table=view.ToTable("MyTable",true,"id","name");

          MyTable 新表的名称,true 表示显示不同的值,将相同的行删除(相当于Sql distinct),

        id name 为新表的列ID.

        4. 枚举DataView

         和枚举DataTabe大同小异

           System.Text.StringBuilder   buffer=new System.Text.StringBuiler();

      foreach(DataColumn dc in auto.Colmns)

     {

              buffer.Append(String.Format“{015}”dc.ColumnName);

     }

      buffer.Append("/r/t");

     foreach(DataRowView dv in view)

     {

             foreach(DataColumn dc in auto.Colmns)

            {

             buffer.Append(String.Format("{0,15}",dv[dc]));  
            }

            buffer.Append("/r/t");

}

textbox1.Text=buffer.ToString();

另外在.net 2.0DataTable对象可以处理XML文件,和DataSet一样,DataTable对象也有ReadXmlWriteXml 的方法,没有具体用过,有机会使用时再做总结。 

------------------------------------------------------------------------------------------------------------------------------------------

通过DataTable获得表的主键

很多情形下我们需要知道表的主键是什么。在ADO.Net中提供了DataTable可以映射数据库的表。于是便可以利用DataTable的属性PrimaryKey,它是DataColumn[] 类型是一个数组。我们可以使用如下的代码

   DataColumn[] cols;
   cols = Table.PrimaryKey;
 //注意不是colsDataColumn数组,不是DataColumn变量。这样做主要是为了处理联合主键的问题。
   for(int i = 0; i < cols.Length; i++)
   {
          MessageBox.Show(cols[i].ColumnName);
   }


按理这个问题就已经解决了,但是cols.Length却是0。原来在默认的情况下填充DataTable时并没有从数据库中取的主键的信息。如何获得主键呢?经过研究发现在填充Dataset的时候可以使用DataAdapterMissingSchemaAction属性帮助我们解决这个问题,于是有如下的代码:

    //使用DataAdapter填充DataTable
    dataadapter.MissingSchemaAction = MissingSchemaAction.AddWithKey;
    dataadapter.Fill(Table);

    DataColumn[] cols;
    cols = Table.PrimaryKey;
    
//注意不是colsDataColumn数组,不是DataColumn变量。这样做主要是为了处理联合主键的问题。
    for(int i = 0; i < cols.Length; i++)
    
{
        MessageBox.Show(cols[i].ColumnName);
    }


这样我们便可以如愿以偿了。MissingSchemaAction属性是确定现有Dataset(或DataTable)架构与传入数据不匹配时需要执行的操作。MissingSchemaAction.AddWithKey是枚举值,它的作用是添加必需的列和主键信息以完成架构,利用它用户可以在每个 DataTable上显式设置主键约束。

------------------------------------------------------------------------------------------------------------------------------------------

DataTable中数据记录的统计

     我们在使用Sql Server这些数据库时,可以轻松的通过SumAverCount等统计出相关结果,那么,在已经把数据检索出来的DataSetDataTable)中呢?特别是通过Web Service获得了DataSet,这个时候,可是没有办法回头去修改Select语句来获取这些统计了。那么在DataSet/DataTable中是否可以进行统计呢?

    
MSDN中,有一篇MS推荐的统计方法,就是逐行对数据进行求和统计,这个方法,其实有等于无(或许这个方法只是针对于DataGrid求取小计用吧),因为这个方法中采用的是DataGridItemDataBind事件来对数据进行累加,同我们手动写代码统计没有什么区别。

本文介绍一个简单的方法,不需要逐条记录进行计算就可以轻松的获得DataTable中的记录统计结果。这个简单的方法就是调用功能强大的DataTable的函数Compute

一、调用说明(仅以C#为例,下同):

public object Compute(string strExpression,string strFilter)

参数:

strExpression:要计算的表达式字符串,基本上类似于Sql Server中的统计表达式

strFilter:统计的过滤字符串,只有满足这个过滤条件的记录才会被统计

二、调用举例:

     以下示例,假设一个产品销售表table,描述某商场中各促销员销售的实际记录,包含字段为:姓名(Name)、性别(Sex0为女,1为男)、生日(Birthday)、销售产品的代码(ProID)、销售的数量(Quantity)、销售价格(Price)。

1。统计所有性别为女的销售员的数量:
table.Compute("Count(*)","Sex=0");

2。统计所有销售员中年龄大于20岁的
table.Compute("Count(*)","Birthday<'"+today);//today
为今天的日期字符串

3。统计销售产品的平均价格
table.Compute("Aver(Price)","true");

4。统计产品代码为1的产品销售数量:
table.Compute("Sum(Quantity)","ProID=1");

5。统计所有产品的销售总金额:
要统计总销售金额,由于table中不存在某项产品某个促销员销售的金额数据,但我们可以通过Quantity*Price来获得。比如:
table.Compute("Sum(Quantity*Price)","true");

这里一个问题是:DataTable的统计功能没有SqlServer强,这个统计是错误的,因为Compute的统计不具备Sum(Quantity*Price)这样数据的功能。那怎么办呢?

对于这样复杂数据的统计,我们可以在DataTable中创建一个新的字段来完成,比如Amount,同时设置该字段的ExpressionQuantity*Price,这样我们就可以使用统计功能了:
table.Compute("Sum(Amount)","true");

以上都是计算每一列的合计,要添加一行求合计可以使用下面的方法:

System.Data.DataRow dataRow=dataSet.Tables[0].NewRow()
'
假设你的DataSetdataSet,表在索引0位置,同时假设你的所有字段都是可以求合计的。

转地址:http://chinesewind.cnblogs.com/archive/2005/11/30/287957.html

System.DataRow dataRow new System.DataRow();
dataRow=DT.NewRow();

然后就是统计了:
int i ;
int fldCnt ;

fldCnt=DT.Cols.Count;

for( i=0 ;i< fldCnt-1;i++)
   dataRow(i)=DT.Compute("Sum("+i.ToString()+")","true");

DT.Rows.Add(dataRow);

好了,大功告成。希望对大家有用。

-------------------------------------------------------------------------------------------

  在下面的例子中实现了3个Join方法,其目的是把两个DataTable连接起来,相当于Sql的Inner Join方法,返回DataTable的所有列。
如果两个DataTable中的DataColumn有重复的话,把第二个设置为ColumnName+"_Second",下面是代码,希望对大家有所帮助。
using System;
using System.Data;
CHINAZ

namespace WindowsApplication1
{
    public class SQLOps
    {
        public SQLOps()
        {           
        }
        public static DataTable Join (DataTable First, DataTable Second, DataColumn[] FJC, DataColumn[] SJC)
        {
            //创建一个新的DataTable
            DataTable table = new DataTable("Join");
            // Use a DataSet to leverage DataRelation
            using(DataSet ds = new DataSet())
CHINAZ

CHINAZ


            {
                //把DataTable Copy到DataSet中

 

                ds.Tables.AddRange(new DataTable[]{First.Copy(),Second.Copy()});

CHINAZ

 

                DataColumn[] parentcolumns = new DataColumn[FJC.Length];

CHINAZ

 

                for(int i = 0; i < parentcolumns.Length; i++)
                {
                    parentcolumns[i] = ds.Tables[0].Columns[FJC[i].ColumnName];
                }
                DataColumn[] childcolumns = new DataColumn[SJC.Length];
                for(int i = 0; i < childcolumns.Length; i++)
                {
                    childcolumns[i] = ds.Tables[1].Columns[SJC[i].ColumnName];
CHINAZ

CHINAZ


                }

 

                //创建关联
                DataRelation r = new DataRelation(string.Empty,parentcolumns,childcolumns,false);
                ds.Relations.Add(r);
CHINAZ

                //为关联表创建列
                for(int i = 0; i < First.Columns.Count; i++)
                {
                    table.Columns.Add(First.Columns[i].ColumnName, First.Columns[i].DataType);
                }
                for(int i = 0; i < Second.Columns.Count; i++)
                {
                    //看看有没有重复的列,如果有在第二个DataTable的Column的列明后加_Second

CHINAZ


                    if(!table.Columns.Contains(Second.Columns[i].ColumnName))
                        table.Columns.Add(Second.Columns[i].ColumnName, Second.Columns[i].DataType);
                    else
                        table.Columns.Add(Second.Columns[i].ColumnName + "_Second", Second.Columns[i].DataType);
                }
                table.BeginLoadData();
                foreach(DataRow firstrow in ds.Tables[0].Rows)

CHINAZ


                {
                    //得到行的数据
                    DataRow[] childrows = firstrow.GetChildRows(r);
                    if(childrows != null && childrows.Length > 0)
                    {
                        object[] parentarray = firstrow.ItemArray;
                        foreach(DataRow secondrow in childrows)

CHINAZ


                        {
                            object[] secondarray = secondrow.ItemArray;
                            object[] joinarray = new object[parentarray.Length+secondarray.Length];
                            Array.Copy(parentarray,0,joinarray,0,parentarray.Length);
                            Array.Copy(secondarray,0,joinarray,parentarray.Length,secondarray.Length); CHINAZ
                            table.LoadDataRow(joinarray,true);
                        }
                    }
                }
                table.EndLoadData();
            }
            return table;
        }
        public static DataTable Join (DataTable First, DataTable Second, DataColumn FJC, DataColumn SJC)

CHINAZ


        {
            return Join(First, Second, new DataColumn[]{FJC}, new DataColumn[]{SJC});
        }
        public static DataTable Join (DataTable First, DataTable Second, string FJC, string SJC)
        {
            return Join(First, Second, new DataColumn[]{First.Columns[FJC]}, new DataColumn[]{First.Columns[SJC]});
        }
    }
}

--------------------------------------------------------------------------------------------------------------------------------------------

DataTable操作中的性能问题 最近的一项工作是关于性能提升方面的。要做的第一个事情是要把很多同类型的DataTable合并到一起,查了很多关于DataTable的相关函数以后,我决定用Merge函数来合并这些DataTable。
DataTable[] srcTables = ... ;
foreach( DataTable src in srcTables )
{
dest.Merge( src ) ;
}
但是测试的结果让我很是失望,性能不是一般的不好。经过调查发现性能的瓶颈在Merge函数这里。后来经过测试,发现如果用下面的代码:
DataTable[] srcTables = ... ;
foreach( DataTable src in srcTables )
{
foreach( DataRow row in src.Rows)
{
dest.ImportRow( row ) ;
}
}

结果让人惊奇的是,下面的代面的速度是上面的代码速度的100倍!

还做了一个事情,就是对DataTable进行filter的时候 ,我的一个同事和我说了以下的代码:
DataView dv = dt.DefaultView ;
dv.RowFilter = filter ;
DataTable result = dv.ToTable() ;
上面的代码是能工作的,但是它的性能一点都不好,后来我把上面的代码改成了:
DataRow[] rows = dv.Select( filter ) ;
foreach( DataRow row in rows )
{
result.ImportRow(row) ;
}

也有数十倍的性能提高。

没想到有这么多的朋友看这个文章,我看了一下Table的Merge函数,下面是关键函数:
private void MergeTable(DataTable src, DataTable dst)
{
int count = src.Rows.Count;
bool flag = dst.Rows.Count == 0;
if (0 < count)
{
Index ndx = null;
DataKey srcKey = new DataKey();
dst.SuspendIndexEvents();
tr

从中我们可以看到Merge做了什么,Merge Table的时候,对每一行,都要有一个对Index进行操作的过程,查看现在要进行insert的row是不是存在重复等等操作。而对我们只想进行append操作的时候,显然是多余的了。

 

我们先看一段WEB Service的代码。

  [WebMethod]
public DataTable GetInfo()
...{
OleDbConnection nwindConn = new OleDbConnection(
"Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data Source=D:Northwind orthwind.mdb;");
OleDbCommand selectCMD =
new OleDbCommand("SELECT CustomerID, CompanyName FROM Customers"
, nwindConn);
selectCMD.CommandTimeout = 30;
OleDbDataAdapter custDA = new OleDbDataAdapter();
custDA.SelectCommand = selectCMD;
DataSet custDS = new DataSet();
custDA.Fill(custDS, "Customers");
return custDS.Tables[0];
}

  在.net 1.1 中,这是典型的一个错误,在.net 1.1 、1.0中,WEB Service 的返回或者输入参数不能是 DataTable,这是一个众人皆知的知识点。原因就是 DataTable 不象DataSet那样支持序列化。在.net 1.1中,我们解决这个问题的方法就是使用DataSet。但是使用DataSet 的时候,经常会有一种杀鸡用牛刀的感觉。

  附:.net 1.1 中使用DataTable作为WEB Service 返回值会报以下异常:

  类型 System.ComponentModel.ISite 的成员 System.ComponentModel.MarshalByValueComponent.Site 是接口,因此无法将其序列化。

  在.net 2.0 中,以上同样的代码,则没有任何问题了。原因是2.0中 DataTable实现了序列化、反序列。

  在VS2005 Beta2 的文档中,我们可以看到2.0 中 DataTable实现了以下接口:

  Explicit Interface Implementations
System.ComponentModel.IListSource.get_ContainsListCollection
System.ComponentModel.IListSource.GetList
System.Xml.Serialization.IXmlSerializable.GetSchema
System.Xml.Serialization.IXmlSerializable.ReadXml
System.Xml.Serialization.IXmlSerializable.WriteXml

  而在1.1中,DataTable 只实现了一个接口:

  Explicit Interfa

而在1.1中,DataTable 只实现了一个接口:

  Explicit Interface Implementations
System.ComponentModel.IListSource.ContainsListCollection

  把DataSet中的一些功能移到 DataTable中,2.0 中还有 Merge 方法,即合并数个数据集。

  DataTable的代码合并参看下面代码。

  private static void DemonstrateMergeTable()
...{
DataTable table1 = new DataTable("Items");
DataColumn column1 = new DataColumn("id", typeof(System.Int32));
DataColumn column2 = new DataColumn("item", typeof(System.Int32));
table1.Columns.Add(column1);
table1.Columns.Add(column2);
table1.PrimaryKey = new DataColumn[] ...{ column1 };
table1.RowChanged += new System.Data.DataRowChangeEventHandler(Row_Changed);
DataRow row;
for (int i = 0; i <= 3; i++)
...{
row = table1.NewRow();
row["id"] = i;
row["item"] = i;
table1.Rows.Add(row);
}
// Accept changes.
table1.AcceptChanges();
DataTable table2 = table1.Clone();
row = table2.NewRow();
row["id"] = 14;
row["item"] = 774;
table2.Rows.Add(row);
row = table2.NewRow();
row["id"] = 12;
row["item"] = 555;
table2.Rows.Add(row);
row = table2.NewRow();
row["id"] = 13;
row["item"] = 665;
table2.Rows.Add(row);
// Merge table2 into the table1.
table1.Merge(table2);
}

  综合上述,.net 2.0 中 DataTable 从后台的默默无问的小兵变成独当一面的大将了。