DataTable小结

 转!foodvc 博客,谢谢!

DataTable 用法

DataTable的细节

DataTable是表格数据块在内存中的表示。虽然可以手动以编程形式构建一个 DataTable,但通常使用 DataSet和定义在 System.Data.OleDb System.Data.SqlClient命名空间中的类型,以动态获得一个 DataTable。表 A-7描述了 DataTable中的一些核心属性。

A-7  DataTable的属性

DataTable属性

   

CaseSensitive

表明表中的字符串比较是否区分大小写。默认的值为 false

ChildRelations

返回 DataTable的子关系 (DataRelationCollection)的集合

Columns

返回属于这个表的列的集合

Constraints

获得表约束的集合 (ConstraintCollection)

DataSet

获得包含这个表的 DataSet

DefaultView

获得表的自定义视图,它可能包含已过滤的视图或游标位置

MinimumCapacity

获得或设置表中行的初始数目 (默认为 25)

ParentRelations

获得这个 DataTable上的父关系的集合

PrimaryKey

获得或设置作为数据表主键的列数组

Rows

返回属于这个表的行集合

TableName

获得或设置表的名称。这个属性还可以被指定为构造函数的参数

A-7 可以帮助您更加清楚地了解 DataTable 的关键部分。要知道这并不是一个传统的类层次结构,说明类型之间 is-a 关系 ( 例如, DataRow 不是派生自 DataRowCollection) 。这个图只是显示了 DataTable 的核心项之间的 has-a 逻辑关系 ( 例如, DataRowCollection 有一些 DataRow 类型 )

A-7  DataTable的集合



构建一个完整的 DataTable

现在您已经了解到最基础的东西,让我们来看一个完整的创建并操作内存中的数据表的例子。假设您想构建一个显示 Cars数据库中当前存货的 DataTable。这个 Inventory表有 4个列: CarID Make Color PetName。同时, CarID列作为这个表的主键 (PK)并支持自动递增。 PetName列允许 null (很遗憾,并不是每个人都和我们一样喜爱自己的车 )。图 A-8显示了该表。

A-8  存货 DataTable

整个过程将从创建一个新的 DataTable类型开始。创建完这个类型后,可以把这个表的名称指定为构造函数的参数。可以用这个名称从所在 DataSet引用这个表,如下所示:

// Create a new DataTable.

DataTable inventoryTable = new DataTable("Inventory");

下一步是以编程方式使用 DataColumnCollection Add()方法插入每列 (使用 DataTable.Columns属性访问 )。下面的逻辑将 CarID Make Color PetName列添加到当前 DataTable (每列的基本数据类型使用 DataType属性设置 )

// DataColumn var.

DataColumn myDataColumn;

// Create CarID column and add to table.

myDataColumn = new DataColumn();

myDataColumn.DataType = Type.GetType("System.Int32");

myDataColumn.ColumnName = "CarID";

myDataColumn.ReadOnly = true;

myDataColumn.AllowDBNull = false;

myDataColumn.Unique = true;

// Set the autoincrement behavior.

myDataColumn.AutoIncrement = true;

myDataColumn.AutoIncrementSeed = 1000;

myDataColumn.AutoIncrementStep = 10;

inventoryTable.Columns.Add(myDataColumn);

// Create Make column and add to table.

myDataColumn = new DataColumn();

myDataColumn.DataType = Type.GetType("System.String");

myDataColumn.ColumnName = "Make";

inventoryTable.Columns.Add(myDataColumn);

// Create Color column and add to table.

myDataColumn = new DataColumn();

myDataColumn.DataType = Type.GetType("System.String");

myDataColumn.ColumnName = "Color";

inventoryTable.Columns.Add(myDataColumn);

// Create PetName column and add to table.

myDataColumn = new DataColumn();

myDataColumn.DataType = Type.GetType("System.String");

myDataColumn.ColumnName = "PetName";

myDataColumn.AllowDBNull = true;

inventoryTable.Columns.Add(myDataColumn);

在添加行之前,花点时间来设置一下表的主键。可以对需要设置的列设定 DataTable.PrimaryKey 属性。由于作为表主键的列可能不止一个,因此要知道 PrimaryKey 的属性需要一个 DataColumn 类型的数组。假设 CarID 列就是 Invetory 表主键的惟一组成部分,如下所示:

// Make the ID column the primary key column.

DataColumn[] PK = new DataColumn[1];

PK[0] = inventoryTable.Columns["CarID"];

inventoryTable.PrimaryKey = PK;

最后但相当重要的是,您需要往表中添加有效的数据。假设有一个合适的 ArrayList保存 Car类型,可以用如下的方式把它填充到表中:

// Iterate over the array list to make rows (remember, the ID is

// autoincremented).

foreach(Car c in arTheCars)

{

DataRow newRow;

newRow = inventoryTable.NewRow();

newRow["Make"] = c.make;

newRow["Color"] = c.color;

newRow["PetName"] = c.petName;

inventoryTable.Rows.Add(newRow);

}

为了显示新的本地内存表,假定有一个 Windows Forms应用程序,包含一个显示 DataGrid的主窗体。如第 11章所示, DataSource属性用于把 DataTable绑定到 GUI上。输出结果如图 A-9所示。

A-9   DataTable绑定到 DataGrid

这儿通过指定要修改的列名称的字符串来添加行。当然还可以指定列的数字索引,在需要迭代每个列时,它特别有用。这样,前面的代码可以更新为如下的代码 (得到同样的最终结果 )

foreach(Car c in arTheCars)

{

// Specify columns by index.

DataRow newRow;

newRow = inventoryTable.NewRow();

newRow[1] = c.make;

newRow[2] = c.color;

newRow[3] = c.petName;

inventoryTable.Rows.Add(newRow);

}

操作 DataTable:删除行

如果您想从数据表中删除一行该怎么做呢?我们可以调用 DataRowCollection类型的 Delete()方法。只要指定要删除行的索引 (或者时 DataRow)就可以。假设您已经按照图 A-10更新了 GUI

A-10  从一个 DataTable中删除行

如果您查看前面的图,就会注意到由于指定了 DataTable的第二行, CarID1020就被删除掉了。下面新按钮的单击事件处理逻辑就是删除内存中 DataTable表中的指定行。

// Remove this row from the DataRowCollection.

protected void btnRemoveRow_Click (object sender, System.EventArgs e)

{

try

{

inventoryTable.Rows[(int.Parse(txtRemove.Text))].Delete();

inventoryTable.AcceptChanges();

}

catch(Exception ex)

{

MessageBox.Show(ex.Message);

}

}

或许将 这个 Delete()方法命名为 MarkedAsDeletable()更好一点,因为这一行只有到 DataTable.AcceptChanges()方法调用后才会真正被删除。实际上, Delete()只是简单地设定一个标记表示“ I am ready to die when my table tells me”。还要明白,如果有一行被标记为删除,那么 DataTable可能会在 AcceptChanges()调用之前拒绝这些修改,如下所示:

// Mark a row as deleted, but reject the changes.

protected void btnRemoveRow_Click (object sender, System.EventArgs e)

{

inventoryTable.Rows[txtRemove.Text.ToInt32()].Delete();

// Do more work. . .

inventoryTable.RejectChanges(); // Restore RowState.

}

操作 DataTable 应用过滤器和排序顺序

或许您想查看 DataTable数据的一个子集,可以用一些过滤条件来指定。例如,如果您只想从这个内存中的 Inventory表中看到某个牌子的汽车该怎么做呢? DataTable类上的 Select()方法恰好提供了这个功能。再次更新您的 GUI,这次允许用户指定一个字符串来表示他们感兴趣查看的车的牌子 ( A-11)

A-11  指定一个过滤器

这个 Select() 方法已经被重载多次,以提供不同的选择语义。传递给 Select() 的最基本参数可以是一个包含有某个条件操作的字符串。首先看一下新按钮的单击事件处理逻辑:

protected void btnGetMakes_Click (object sender, System.EventArgs e)

{

// Build a filter based on user input.

string filterStr = "Make='" + txtMake.Text + "'";

// Find all rows matching the filter.

DataRow[] makes = inventoryTable.Select(filterStr);

// Show what we got!

if(makes.Length = = 0)

MessageBox.Show("Sorry, no cars. . .", "Selection error!");

else

{

string strMake = null;

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

{

DataRow temp = makes[i];

strMake += temp["PetName"].ToString() + ""n";

}

MessageBox.Show(strMake, txtMake.Text + " type(s):");

}

}

这儿,您首先建立一个基于相关的文本框值的过滤器条件。如果您指定 BMW,那么过滤器条件就是 Make = ‘BMW’。把这个过滤器发送给 Select()方法后,就会得到一个 DataRow类型的数组,这个数组表示了匹配每个符合过滤条件的行,如图 A-12所示。

A-12  过滤后的数据

可以用很多相关的操作符组成一个过滤字符串。例如,如果想查找所有 ID大于 1030的车怎么做呢?您可以编写如下的代码 (见图 A-13的输出结果 )

// Now show the pet names of all cars with ID greater than 1030.

DataRow[] properIDs;

string newFilterStr = "ID > '1030'";

properIDs = inventoryTable.Select(newFilterStr);

string strIDs = null;

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

{

DataRow temp = properIDs[i];

strIDs += temp["PetName"].ToString()

+ " is ID " + temp["ID"] + ""n";

}

MessageBox.Show(strIDs, "Pet names of cars where ID > 1030");

A-13  指定一个数据范围

模拟标准 SQL语法编写过滤逻辑。为了验证这一点,假设想根据 pet名称的字母顺序来获得前面 Select()命令的结果。在 SQL术语中,这会被解释为基于 PetName列进行排序。幸运的是, Select()方法已经被重载过,它可以传递一个排序条件,如下所示:

makes = inventoryTable.Select(filterStr, "PetName");

这样会返回图 A-14所示的信息。

A-14  已排序的数据

如果您想用降序来对结果排序,调用 Select(),如下所示:

// Return results in descending order.

makes = inventoryTable.Select(filterStr, "PetName DESC");

一般来说,排序字符串是列名后跟着“ ASC (升序,默认设置 )或“ DESC (降序 )。如果需要的话,可以用逗号来把多个列分开排序。

操作 DataTable:更新行

您需要了解的关于 DataTable的最后一个方面就是怎样用新值更新已有的行。一个方法就是先用 Select()方法 获得符合给定过滤条件的行。一旦获得这些 DataRow,就对它们作相应的修改。例如,假定有一个新按钮在被单击后,搜索 DataTable中所有 Make BMW的行。一旦标识这些项后,就可以把 Make从“ BMW”改为“ Colt”。

// Find the rows you want to edit with a filter.

protected void btnChange_Click (object sender, System.EventArgs e)

{

// Build a filter.

string filterStr = "Make='BMW'";

string strMake = null;

// Find all rows matching the filter.

DataRow[] makes = inventoryTable.Select(filterStr);

// Change all Beemers to Colts!

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

{

DataRow temp = makes[i];

strMake += temp["Make"] = "Colt";

makes[i] = temp;

}

}

这个 DataRow类也提供了 BeginEdit() EndEdit() CancelEdit()方法,这些方法可以在任何相关的验证规则被临时挂起时对一个行的内容进行编辑。在前面的逻辑中,每一行都用一个指派作了验证 (而且如果从 DataRow中捕获事件的话,这些事件会在每次修改时触发 )。在对某个 DataRow调用 BeginEdit()时,这一行就被设置在编辑模式下。这时您可以根据需要来作些改动,并调用 EndEdit()提交修改或者 CancelEdit()把所作的修改回滚到原先的版本。例如:

// Assume you have obtained a row to edit.

// Now place this row in edit mode'.

rowToUpdate.BeginEdit();

// Send the row to a helper function, which returns a Boolean.

if( ChangeValuesForThisRow( rowToUpdate) )

{

rowToUpdate.EndEdit(); // OK!

}

else

{

rowToUpdate.CancelEdit(); // Forget it.

}

虽然您可以随意地对某一 DataRow手动调用这些方法,但如果把一个 DataGrid绑定到 DataTable,这些成员就可以被自动地调用。例如,如果您想从 DataGrid中选择一行进行编辑的话,该行就会自动处于编辑模式下。当把焦点换到另一行时,就会自动调用 EndEdit()。为了测试这个行为,假设您已经手动地使用 DataGrid把每个车更新为某个 Make( A-15)

如果现在您想查询所有的 BMW,消息对话框会正确地返回所有行,因为关联到这个 DataGrid的底层 DataTable已经被自动更新了 ( A-16)

            

A-15  DataGrid中编辑行                    A-16  Inventory DataTable

 
如果我想限制取前面的50行,该怎么办呢?
DataRow[] properIDs;
string newFilterStr = "ID > '1030'";
properIDs = inventoryTable.Select(newFilterStr);
如果我想限制取前面的50行,该怎么办呢?
可以用SQL语句实现(select top 50 * from tabalName),最方便,
如果要用上面的方法,可以给DataTable中插入一个自增行(index),用它去判断.
也可以这样写.
     private  DataTable SelectTop( int  top, DataTable dt)
    {
        
if  (dt.Rows.Count  <  top)  return  dt;

        DataTable newTable 
=   new  DataTable();
        
        
int  columns  =  dt.Columns.Count;
        
string [] col  =   new   string [columns];

        
// 取得要筛选表的所有列名
         for  ( int  c  =   0 ; c  <  columns; c ++ )
        {
            col[c] 
=  dt.Columns[c].ColumnName;            
        }

        
// 创建新表的结构
         foreach  ( string  columnName  in  col)
        {
            newTable.Columns.Add(columnName);
        }

        
// 选取所有行
        DataRow[] rows  =  dt.Select( " 1=1 " );
        DataRow newRow;
        
for  ( int  i  =   0 ; i  <  top; i ++ )
        {
            newRow 
=  newTable.NewRow();
            
foreach  ( string  columnName  in  col)
            {
                newRow[columnName] 
=  rows[i][columnName].ToString();
            }

            newTable.Rows.Add(newRow);
        }
        dt.Dispose();        
        
return  newTable;
    }

 

posted on 2008-03-27 10:21 freeliver54 阅读(279) 评论(3)  编辑 收藏 所属分类: VS技術實踐

评论

 

DataTable的过滤器的三种做法
http://blog.csdn.net/orichisonic/archive/2007/12/03/1913041.aspx
前两种是公司老大平时用的

dataTable.select和dataview.filter

后面这种是用的

CurrencyManager cm = (CurrencyManager)BindingContext[ConditionGridView.DataSource];
int rowCount = cm.Count;

for (int row = 0; row < rowCount; ++row)
{
DataGridViewRow dgvr = ConditionGridView.Rows[row];
int tempi = int.Parse(dgvr.Cells[1].Value.ToString());
DataGridViewRow dgvr2 = ConditionGridView.Rows[row + 1];
int tempi2 = int.Parse(dgvr2.Cells[1].Value.ToString());
DataTable dt;

if (currentExp > tempi && currentExp < tempi2)
{
cm.SuspendBinding();//这是挂起数据的绑定,是必要有的,
dgvr.Visible = true;
dgvr2.Visible = true;
num = 1;

tempi3 = int.Parse(dgvr.Cells[0].Value.ToString());
}
else
{
cm.SuspendBinding();
if (num == 1)
{

dgvr2.Visible = false;
num = 0;
}
else if (num == 0)
{
dgvr.Visible = false;
dgvr2.Visible = false;

}


}

  回复   引用   查看     

#2楼   [楼主 ] 2008-03-27 10:40 freeliver54       

过滤DataTable的Rows的重复值
http://www.gxhaoqi.com/xw/html/601/
过滤DataTable的Rows的重复值
// 方法1
string sFormater = "{0}, {1}";
string sKeys = null;
string sPrevKeys = null;
// Key项目排序
DataRow[] rows = table.Select("", "Key0, Key1");
foreach (DataRow row in rows)
...{
sKeys = string.Format(sFormater, row["Key0"].ToString(), row["Key1"].ToString());
if (!sKeys.Equals(sPrevKeys))
...{
tagetTable.ImportRow(row);
}
sPrevKeys = sKeys;
}

// 方法2
string sSelectFormater = "{0}, {1}";
foreach (DataRow row in table.Rows)
...{
if (tagetTable.Select(string.Format(sSelectFormater, "Key0", "Key1")).Length == 0)
...{
tagetTable.ImportRow(row);
}
}

table = tagetTable;

// 方法3
string sFormater = "{0}, {1}";
DataRow row;
string sSelectFormater = "Key0 = {0}, Key1 = {1}";
for (int i = 0; i < table.Rows.Count; i++)
...{
if (table.Select(string.Format(sSelectFormater, row["Key0"].ToString(), row["Key1"].ToString())).Length > 1)
...{
table.Rows.Remove(row);
i--;
}
}

// 方法3少一行
...
row = table.Rows[i];
...

// 方法4
DataView view = table.DefaultView;
DataTable tagetTable= view.ToTable(true, "column1", "column2", ...);

方法4是最简单的方法,感觉很聪明的使用了dataview的toTable方法。


本文作者: 修改时间:2007-12-6 9:24:47
,DataTable的过滤器的三种做法
http://blog.csdn.net/orichisonic/archive/2007/12/03/1913041.aspx
前两种是公司老大平时用的

dataTable.select和dataview.filter

后面这种是用的

CurrencyManager cm = (CurrencyManager)BindingContext[ConditionGridView.DataSource];
int rowCount = cm.Count;

for (int row = 0; row < rowCount; ++row)
{
DataGridViewRow dgvr = ConditionGridView.Rows[row];
int tempi = int.Parse(dgvr.Cells[1].Value.ToString());
DataGridViewRow dgvr2 = ConditionGridView.Rows[row + 1];
int tempi2 = int.Parse(dgvr2.Cells[1].Value.ToString());
DataTable dt;

if (currentExp > tempi && currentExp < tempi2)
{
cm.SuspendBinding();//这是挂起数据的绑定,是必要有的,
dgvr.Visible = true;
dgvr2.Visible = true;
num = 1;

tempi3 = int.Parse(dgvr.Cells[0].Value.ToString());
}
else
{
cm.SuspendBinding();
if (num == 1)
{

dgvr2.Visible = false;
num = 0;
}
else if (num == 0)
{
dgvr.Visible = false;
dgvr2.Visible = false;

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值