ReadOnlyException DataTable DataRow“列 X 是只读的。”

发布于 2024-10-26 12:35:44 字数 3135 浏览 0 评论 0原文

我有一小段代码最初一遍又一遍地创建一个 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;
}
  • 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;
}

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

是因为 SqlConnection 仍然打开还是 SqlDataAdapter 在幕后做某事?

I've got a short piece of code that originally created an SqlDataAdapter object over and over.

Trying to streamline my calls a little bit, I replaced the SqlDataAdapter with an SqlCommand and moved the SqlConnection outside of the loop.

Now, whenever I try to edit rows of data returned to my DataTable, I get a ReadOnlyException thrown that was not thrown before.

NOTE: I have a custom function that retrieves the employee's full name based on their ID. For simplicity here, I used "John Doe" in my example code below to demonstrate my point.

ExampleQueryOld works with the SqlDataAdapter; ExampleQueryNew fails with the ReadOnlyException whenever I try to write to an element of the DataRow:

  • ExampleQueryOld

This works and has no issues:

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;
}
  • ExampleQueryNew

This example throws the 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;
}

Why can I write to the DataRow element in one case, but not in the other?

Is it because the SqlConnection is still open or is the SqlDataAdapter doing something behind the scene?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

三生池水覆流年 2024-11-02 12:35:44

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

使用 DataReader 填充表格来加载架构。因此,index 列是只读的(可能是因为它是主键),并且该信息被加载到 DataTable 中。从而防止您修改表中的数据。

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

foreach (System.Data.DataColumn col in tab.Columns) col.ReadOnly = false; 

using DataAdapter.Fill does not load the database schema, which includes whether a column is a primary key or not, and whether a column is read-only or not. To load the database schema, use DataAdapter.FillSchema, but then that's not your questions.

using DataReader to fill a table loads the schema. So, the index column is read-only (probably because it's the primary key) and that information is loaded into the DataTable. Thereby preventing you from modifying the data in the table.

I think @k3b got it right; by setting ReadOnly = false, you should be able to write to the data table.

foreach (System.Data.DataColumn col in tab.Columns) col.ReadOnly = false; 
呆萌少年 2024-11-02 12:35:44

在尝试不同的方法时,我不断遇到相同的异常。最终对我有用的是将列的 ReadOnly 属性设置为 false 并更改 Expression 列的值而不是 row[index] = "new value";

I kept getting the same exception while trying different approaches. What finally worked for me was to set the column's ReadOnly property to false and change the value of the Expression column instead of row[index] = "new value";

往事随风而去 2024-11-02 12:35:44

在 VB 中,不要通过引用传递只读 DataRow 项

遇到这种情况的可能性很低,但我正在处理一些 VB.NET 代码并得到了 ReadOnlyException

我遇到这个问题是因为代码将 DataRow Item 传递给 Sub ByRef。仅通过引用传递的行为就会触发异常。

Sub Main()

    Dim dt As New DataTable()
    dt.Columns.Add(New DataColumn With {
        .ReadOnly = True,
        .ColumnName = "Name",
        .DataType = GetType(Integer)
    })

    dt.Rows.Add(4)

    Try
        DoNothing(dt.Rows(0).Item("Name"))
        Console.WriteLine("All good")
    Catch ex As Exception
        Console.WriteLine(ex.Message)
    End Try 

End Sub

Sub DoNothing(ByRef item As Object) 
End Sub 

输出

Column 'Name' is read only

C-sharp

您甚至无法在 C# 中编写这样的代码。 DoNothing(ref dt.Rows[0].Item["Name"]) 会给您一个编译时错误。

In VB, don't pass a read-only DataRow Item by reference

The likelihood that you'll run into this is low, but I was working on some VB.NET code and got the ReadOnlyException.

I ran into this issue because the code was passing the DataRow Item to a Sub ByRef. Just the act of passing-byref triggers the exception.

Sub Main()

    Dim dt As New DataTable()
    dt.Columns.Add(New DataColumn With {
        .ReadOnly = True,
        .ColumnName = "Name",
        .DataType = GetType(Integer)
    })

    dt.Rows.Add(4)

    Try
        DoNothing(dt.Rows(0).Item("Name"))
        Console.WriteLine("All good")
    Catch ex As Exception
        Console.WriteLine(ex.Message)
    End Try 

End Sub

Sub DoNothing(ByRef item As Object) 
End Sub 

Output

Column 'Name' is read only

C-sharp

You can't even write code like this in C# . DoNothing(ref dt.Rows[0].Item["Name"]) gives you a compile time error.

那片花海 2024-11-02 12:35:44

打开数据集的 yourdataset.xsd 文件。单击表或对象,然后单击需要更改只读属性的特定列。
其简单的解决方案。

open the yourdataset.xsd file of your data set. click on the table or object and click on the specific column which readonly property need to be changed.
its simple solutions.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文