先列出正确的写法,如果你只想马上改错就先复制吧,

    protected void deleteDataRow(int RowID,DataTable dt)
    {
        
for (int i = dt.Rows.Count - 1; i >= 0; i--)
        {
            
if (Convert.ToInt32(dt.Rows[i]["RowID"]) == RowID)
                dt.Rows.RemoveAt(i);
        }
    }

   

如果你有时间想学习一下就继续看下面列出可能出错的可能性吧。

  1.如果只是想删除datatable中的一行,可以用DataRowdelete,但是必须要删除后让DataTable知道,所以就要用到.AcceptChanges()方法,原因是这种删除只是标识性删除,就像我们通常在数据库中用到的IsDelete字段。

  2.彻底删除就要用到datatable.Rows.Remove(DataRow dr)方法,同理也只是删除一行可以,如果要循环删除请继续往下看。

  3.循环彻底删除就要用.Rows.RemoveAt(int index)方法,所以如果你是foreach的爱好者,在此请你换换口味,还有如果你是fori++的忠实fans也希望你能换个思维。先看一下上面程序的正向写法(错误的,不可用)

        for (int i = 0, j = dt.Rows.Count; i < j; i++)
        {
            
if (Convert.ToInt32(dt.Rows[i]["RowID"]) == RowID)
                dt.Rows.RemoveAt(i);
        }

   

  这个的错误在于datatableRemoveAt()会在删除后更新dataTableindex,所以你要删除的index可能已经不是你的符合Convert.ToInt32(dt.Rows[i]["RowID"]) == RowIDindex了,甚者还会抛出异常,说你访问的index不存在。

  所以要从DataTable的下面网上查找删除,这样即使这行符合条件被删除了,上面的行依旧不受影响。

说了这么多,不知道你明白了吗?其实现在写这种文章显得有点"弱智",技术学多了,越来越觉得自己的基础不够扎实,希望通过在此记录一下可以督促一下自己,也希望能给初学者带去丝丝帮助。

   

 

 

 

五、操纵dataset
DataSetDataRow是其所有数据的基本存放位置,它主要是由一个值数组组成,代表DataTable单独一行。
DataRow
中主要包括一下几种信息:1、行中每一列的当前值,2、行中每一列的原始值,3、行状态,4、父行与子行间的链接

初始化一个DataRow
DataTable dataTabledataSet.Tables[0];
DataRow newRow=dataTable.NewRow(); //
dataTable生成DataRow可以利用dataTable里面的模式
dataTable.Rows.Add(newRow);


删除行:
DataTable.Rows.Remove(行实例);
DataTable.Rows.RemoveAt(
行号);
DataRow.Delete(); //
行自身移除


读写DataRow的值:
row["
列名"]row[列号]均可引用其中的一个属性
DataColumn a=dataTable.Columns("
列名"); //可以获得一个列


对行进行批处理更改:
BeginEdit()
开始更改,EndEdit()结束更改,同时将更改结果写入DataSetCancelEdit(),取消更改
例如:
row.BeginEdit();
row进行更改
row.EndEdit();

将数据批量加载到DataTable
dataTable.BeginLoadData();
dataTable.LoadDataRow(row1,false); //
第二个参数为true时,调用dataTable.AcceptChanges()时接受更改,为false直接添加
……
dataTable.EndLoadData();
使用这种数据加载方式可以在数据加载期间屏蔽所有的数据约束,索引也不会予以维护,极大的加快了数据加载速度

行的版本:
current
:当前值
default
:根据操作的不同决定行的default
original
:最后一次调用AcceptChanges()之后的值
proposed
:调用AcceptChanges()之前被更改的值
例如要获得行的original值:
String oldString=row("FirstName",DataRowVersion.original);

行的状态:
row.RowState
获得行的状态,例如删除后变成Deleted,数据存储更新后变为unchanged

六、DataSet导航
ADO.NET中每个表都保持其相对独立性,允许在行级上导航不同表之间的相关行(向下导航到子行,向上导航的父行)
DataRow[] invoiceRows=custRow.GetChildRows("Customer_invoice"); //通过关系导航到子行

七、DataView
DataView
就时数据视图,为数据库结构提供了外模式的实现。
同时DataView也可以为窗体控件和Web控件提供数据绑定功能,在每一个DataTable中内建了一个DataView为:DataTable.DefaultView();

创建DataView
DataView sortedView=new DataView(dataTable);

DataView进行排序
dataTable.DefaultView.sort="lastName";
dataTable.DefaultView.sort="lastName,FirstName DESC";

DataView进行筛选:
1
、通过对其中的RowFilter属性设置可以实现筛选
dataTable.DefaultView.RowFilter="Vendor='Rawlings'";
不过筛选表达式只能设置成比较简单的表达式,功能有限,不过可以满足基本的要求。
同样在DataTable里面也可以进行简单的搜索,返回一个DataRow数组,例:
DataRow[] compoundRows=dataTable.select("Vendor='wilson' AND price>20.00)
2
、通过RowState来筛选
dataTable.DefaultView.RowStateFilter="DataViewRowState.originalRows"
可以筛选出符合要求状态的row

DataView进行搜索:
相对于DataView使用RowFilter进行筛选得到一个矩形数据集,使用FindFindRows可以更准确的查找到与特定键相匹配的行
搜索的时候必须首先设置DataViewsort属性:
int found=dataTable.DefaultView.Find("wilson"); //
获得行的位置
DataRowView[] rows=dataTable.DefaultView.FindRows("Rawlings") //
过得一个row数组

八、更新DB
DataSet中,每一个DataTable对应着一个DataAdapterDataAdapter.Update()时,DataTable自动更新。
更新的时候可以使用CommandBuilder自动根据DataSet的变化生成更新的SQL命令
SqlCommandBuilder bldr=new SqlCommandBuilder(dataAdapter);
dataAdapter.Update(custTable);
不过Update接受DataSet参数并不更新DataSet而是更新DataSet中的一个叫"Table"的表
使用CommandBuilder进行更新的时候要注意一下几点:
1
SelectCommand必须有效
2
、必须有主码
3
、若SelectCommand填充DataTable后架构发生改变,应该在Update()之前调用CommandBuilder.RefreshSchema();
4
、更新DB时不受关系、约束或者DataSet中其他表的影响
虽然使用CommandBuilder比较方便,不用自己写更新命令,但自动生成的命令性能不高,这时可以考虑自己编写存储过程或直接使用带参数的sql语句,例如:
String insQry="Insert into Customer(CustomerID) Values (@Customer)";
SqlCommand insCmd=conn.CreateCommand();
insCmd.CommandText=insQry;
SqlParameterCollection insParams=insCmd.Parameters;
insParams.Add("@CustomerID",SqlDbType.UniqueIdentifier,0,"CustomerID");
dataAdapter.InsertCommand=insCmd;
dataAdapter.Update();
dataAdapter.Update()更新时还可以控制更新的范围:
dataAdapter.Update(invTable.GetChanges(DataRowState.Deleted); //
只更新被删除的部分

九、事务
tx=conn.BeginTransaction(IsolationLevel.Serializable);
invDA.SelectCommand.Transaction=tx;
事务操作
tx.Commit();
提交 //tx.Rollback();事务回滚

十、数据绑定
简单版本:(对文本框、标签等)
{Controls}.DataBindings.Add("{Property}",{dataSource},"{dataMember}");
其中Property为待绑定的属性,dataSourceDataViewDataTabledataMemberdataSource其中的某个属性

复杂版本:(对ListBoxComboBox等)
要分别设置各个属性实现绑定:
DataSource=
支持IList的一个对象(DataTableDataView
DisplayMember
:待显示的DataSource中的一个属性
ValueMember
:确定在DataSource中引用哪一个数据行,即实现与DisplayMember的名值对应

DataGrid
绑定:
1
、可以设置DataSource属性实现静态绑定
2
、可以使用SetDataBinding函数实现动态绑定

同时DataGrid支持主控/详细表显示
masterGrid.setDataBinding(customerTable,"");
detailGrid.setDataBinding(customerTable,"Customer_Invoices") //
第二个属性要设置成关系约束
这样在主表中选择一行,在子表中就根据主表行中外码在子表中找到相应行

绑定之后,绑定项中就有一个CurrencyManager属性实现游标功能
BindingContext[CustomerTable]
返回一个CurrencyManager对象,其中的Position属性可以更改,实现游标的移动。