.NET(CF)DataRow如何自发地将所有值设置为DBNull?

时间:2011-10-19 20:02:48

标签: .net compact-framework strongly-typed-dataset

我正在使用Compact Framework中的.NET DataSet。单个DataSet包含四个或五个具有轻量数据用量的表(每个表的行数为几行)。主数据表(所有外键约束所基于的)包含单个行。 DataSet作为XML文件持久保存到磁盘(使用DataSet.WriteXML)。

我们发现,每隔一段时间,DataRow的值都会因为没有明显原因而被设置为DBNull。更重要的是,当数据再次持久化时,主数据表的单行将被写入而没有数据。

例如,我们希望看到:

<MyDataSet>
<MyTypedDataRow id="1" data1="data" data2="more data" />
...

其中“data1”和“data2”是不可为空的列。相反,我们很少得到:

<MyDataSet>
<MyTypedDataRow />
...

这应该是不可能的。

我们的环境确实使用多线程,但对DataSet的访问受到严格的线程保护。

当我试图在调试器中发生这种情况时,由于表的约束,我的所有努力都会遇到错误。

有没有人对如何发生这种情况有任何想法?

感谢您的光临。


编辑:我没有提到的一件事可能是一个促成因素。这是一个使用Visual Studio设计器制作的强类型DataSet,但在创建后经历了重大的手动修改(不要责怪我;它在我的时间之前)。显然,这可能会产生一些意想不到的副作用......但即使我们尝试过,我也看不出这个问题是如何发生的。

2 个答案:

答案 0 :(得分:0)

这当然是讽刺的,我想其他事情可能正在发生。

为了帮助您进行测试,我建议您联系一些可以检查的事件处理程序。

这是一个你可以使用的测试类,适用于WM5和CF 2.0。

查看数据丢失时发生的情况。

class TestOnly {

  public DataTable Table { get; set; }

  public TestOnly() {
    Table = new DataTable();
    Table.Disposed += new EventHandler(Table_Disposed);
    Table.ColumnChanging += new DataColumnChangeEventHandler(Table_ColumnChanging);
    Table.RowChanging += new DataRowChangeEventHandler(Table_RowChanging);
    Table.RowDeleting += new DataRowChangeEventHandler(Table_RowDeleting);
    Table.TableClearing += new DataTableClearEventHandler(Table_TableClearing);
  }

  bool myAct = false;

  void Table_TableClearing(object sender, DataTableClearEventArgs e) {
    Console.WriteLine("Table {0} clearing. {1}", e.TableName, DateTime.Now);
  }

  void Table_ColumnChanging(object sender, DataColumnChangeEventArgs e) {
    if (!myAct) {
      e.Row.CancelEdit();
      Console.WriteLine("Edit of {0} cancelled. {1}", e.Column.Caption, DateTime.Now);
    }
  }

  void Table_RowChanging(object sender, DataRowChangeEventArgs e) {
    if (!myAct) {
      e.Row.CancelEdit();
      Console.WriteLine("DataRow Action {0} cancelled. {2}", e.Action, DateTime.Now);
    }
  }

  void Table_RowDeleting(object sender, DataRowChangeEventArgs e) {
    if (!myAct) {
      e.Row.CancelEdit();
      Console.WriteLine("DataRow Action {0} cancelled. {2}", e.Action, DateTime.Now);
    }
  }

  void Table_Disposed(object sender, EventArgs e) {
    Console.WriteLine("Table Disposed at {0}.", DateTime.Now);
  }


}

答案 1 :(得分:0)

我已经发现了一些关于这个问题的更多信息,我认为这将解决我的问题。

我创建了一个简单的测试应用程序,其中包含一个设计器构建的强类型DataSet。该应用程序在启动时产生三个线程。两个修改同一列中的值,然后读入值,并重复ad infintum。第三个线程不断地将DataSet保存到磁盘。

最终(在几秒到一分钟的范围内),线程会打开DataSet,因此它会引发文本异常:&#34; DataTable内部索引已损坏:5&#34;。如果我继续吞下这些异常,最终我会遇到一个&#34; InvalidCastException&#34;,其中无法从行中读取数据,因为它是DBNull。当发生这种情况时,我可以看到整行是DBNull,甚至是主键。

有趣的是,&#34; WriteXML&#34;方法在此状态下抛出异常;文件可以这种方式保存,即使它违反了所有约束条件。

在我的实际应用中,我认为我的防线在这个领域是不够的。我不知道这是否是ADO.NET内部的错误,或者只是围绕ADO.NET对象进行良好的线程保护的论据。无论哪种方式,这都是一个非常烦人的问题。