ReadOnlyException DataTable DataRow"列X是只读的."

jp2*_*ode 44 c# datatable sqlcommand sqldataadapter

我有一小段代码,它最初反复创建了一个SqlDataAdapter对象.

尝试简化我的调用,我用SqlCommand替换了SqlDataAdapter,并将SqlConnection移到了循环之外.

现在,每当我尝试编辑返回到我的DataTable的数据行时,我都会抛出之前未抛出的ReadOnlyException.

注意:我有一个自定义函数,可根据其ID检索员工的全名.为简单起见,我在下面的示例代码中使用了"John Doe"来证明我的观点.

ExampleQueryOldSqlDataAdapter一起使用 ; 每当我尝试写入DataRow的元素时,ExampleQueryNew都会因ReadOnlyException 失败:

  • ExampleQueryOld

这有效,没有问题:

public static DataTable ExampleQueryOld(string targetItem, string[] sqlQueryStrings) {
  DataTable bigTable = new DataTable();
  for (int i = 0; i < sqlQueryStrings.Length; i++) {
    string sqlText = sqlQueryStrings[i];
    DataTable data = new DataTable(targetItem);
    using (SqlDataAdapter da = new SqlDataAdapter(sqlText, Global.Data.Connection)) {
      try {
        da.Fill(data);
      } catch (Exception err) {
        Global.LogError(_CODEFILE, err);
      }
    }
    int rowCount = data.Rows.Count;
    if (0 < rowCount) {
      int index = data.Columns.IndexOf(GSTR.Employee);
      for (int j = 0; j < rowCount; j++) {
        DataRow row = data.Rows[j];
        row[index] = "John Doe"; // This Version Works
      }
      bigTable.Merge(data);
    }
  }
  return bigTable;
}
Run Code Online (Sandbox Code Playgroud)
  • ExampleQueryNew

此示例抛出ReadOnlyException:

public static DataTable ExampleQueryNew(string targetItem, string[] sqlQueryStrings) {
  DataTable bigTable = new DataTable();
  using (SqlConnection conn = Global.Data.Connection) {
    for (int i = 0; i < sqlQueryStrings.Length; i++) {
      string sqlText = sqlQueryStrings[i];
      using (SqlCommand cmd = new SqlCommand(sqlText, conn)) {
        DataTable data = new DataTable(targetItem);
        try {
          if (cmd.Connection.State == ConnectionState.Closed) {
            cmd.Connection.Open();
          }
          using (SqlDataReader reader = cmd.ExecuteReader()) {
            data.Load(reader);
          }
        } catch (Exception err) {
          Global.LogError(_CODEFILE, err);
        } finally {
          if ((cmd.Connection.State & ConnectionState.Open) != 0) {
            cmd.Connection.Close();
          }
        }
        int rowCount = data.Rows.Count;
        if (0 < rowCount) {
          int index = data.Columns.IndexOf(GSTR.Employee);
          for (int j = 0; j < rowCount; j++) {
            DataRow row = data.Rows[j];
            try {
              // ReadOnlyException thrown below: "Column 'index'  is read only."
              row[index] = "John Doe";
            } catch (ReadOnlyException roErr) {
              Console.WriteLine(roErr.Message);
            }
          }
          bigTable.Merge(data);
        }
      }
    }
  }
  return bigTable;
}
Run Code Online (Sandbox Code Playgroud)

为什么我可以在一种情况下写入DataRow元素,而不是在另一种情况下写入?

是因为SqlConnection仍处于打开状态还是SqlDataAdapter在场景后面做了什么?

Fun*_*eng 87

using DataAdapter.Fill不加载数据库模式,其中包括列是否为主键,以及列是否为只读.要加载数据库架构,请使用DataAdapter.FillSchema,但那不是您的问题.

通过DataReader填写表格加载模式.因此,该index列是只读的(可能是因为它是主键)并且该信息被加载到DataTable.从而阻止您修改表中的数据.

我认为@ k3b做对了; 通过设置ReadOnly = false,您应该能够写入数据表.

foreach (System.Data.DataColumn col in tab.Columns) col.ReadOnly = false; 
Run Code Online (Sandbox Code Playgroud)

  • @ jp2code您可以创建一个新表,只复制没有架构信息的数据.如果它只是您想要更改的特定属性(如只读标志),那么最好只设置该属性的值. (2认同)