ReadOnlyException DataTable DataRow «Столбец X только для чтения». - PullRequest
43 голосов
/ 25 марта 2011

У меня есть небольшой фрагмент кода, который первоначально создавал объект SqlDataAdapter снова и снова.

Пытаясь немного упростить свои вызовы, я заменил SqlDataAdapter на SqlCommand и переместил SqlConnection за пределы цикла.

Теперь, когда я пытаюсь отредактировать строки данных, возвращаемых в мою DataTable , я получаю ReadOnlyException , который не был брошен ранее.

ПРИМЕЧАНИЕ. У меня есть пользовательская функция, которая получает полное имя сотрудника на основании его идентификатора. Для простоты здесь я использовал «Джон Доу» в своем примере кода ниже, чтобы продемонстрировать свою точку зрения.

ExampleQueryOld работает с SqlDataAdapter ; ExampleQueryNew завершается с ошибкой ReadOnlyException всякий раз, когда я пытаюсь выполнить запись в элемент DataRow :

  • 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 что-то делает за сценой?

Ответы [ 4 ]

85 голосов
/ 27 марта 2011

при использовании DataAdapter.Fill не загружает схему базы данных, в которой указывается, является ли столбец первичным ключом или нет, а также доступен ли столбец только для чтения. Чтобы загрузить схему базы данных, используйте DataAdapter.FillSchema, но тогда это не ваши вопросы.

с использованием DataReader для заполнения таблицы загружает схему. Таким образом, столбец index доступен только для чтения (возможно, потому что это первичный ключ), и эта информация загружается в DataTable. Тем самым вы не можете изменять данные в таблице.

Я думаю, что @ k3b понял все правильно; установив ReadOnly = false, вы сможете записывать данные в таблицу.

foreach (System.Data.DataColumn col in tab.Columns) col.ReadOnly = false; 
1 голос
/ 17 октября 2016

Я продолжал получать одно и то же исключение, пытаясь использовать разные подходы.Наконец мне удалось установить для свойства столбца ReadOnly значение false и изменить значение столбца Выражение вместо строки [index] = "новое значение";

0 голосов
/ 29 ноября 2018

В VB не передавайте доступный только для чтения элемент DataRow по ссылке

Вероятность того, что вы столкнетесь с этим, мала, но я работал над некоторым кодом VB.NET и получил ReadOnlyException.

Я столкнулся с этой проблемой, поскольку код передавал элемент DataRow в 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"]) выдает ошибку времени компиляции.

0 голосов
/ 30 августа 2014

откройте файл yourdataset.xsd вашего набора данных. щелкните по таблице или объекту и щелкните по конкретному столбцу, свойство которого только для чтения необходимо изменить. его простые решения.

...