ReadOnlyException DataTable DataRow "Столбец X доступен только для чтения".
У меня есть короткий фрагмент кода, который изначально создавал объект SqlDataAdapter снова и снова.
Попытка немного упростить мои вызовы, я заменил SqlDataAdapter на SqlCommand и переместил SqlConnection вне цикла.
Теперь, всякий раз, когда я пытаюсь редактировать строки данных, возвращенные в мой DataTable, я получаю бросок ReadOnlyException, который не был брошен раньше.
ПРИМЕЧАНИЕ. У меня есть настраиваемая функция, которая извлекает полное имя сотрудника на основе их идентификатора. Для простоты здесь я использовал "John Doe" в моем примере кода ниже, чтобы продемонстрировать свою точку зрения.
ExampleQueryOld работает с SqlDataAdapter; ExampleQueryNew терпит неудачу с ReadOnlyException, когда я пытаюсь записать элемент DataRow:
Это работает и не имеет проблем:
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;
}
В этом примере генерируется исключение 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 делает что-то за сценой?
Ответы
Ответ 1
с помощью DataAdapter.Fill
не загружается схема базы данных, которая включает в себя, является ли столбец первичным ключом или нет, и является ли столбец только для чтения или нет. Чтобы загрузить схему базы данных, используйте DataAdapter.FillSchema
, но тогда это не ваши вопросы.
используя DataReader
, чтобы заполнить таблицу, загружает схему. Таким образом, столбец index
доступен только для чтения (возможно, потому, что это первичный ключ) и эта информация загружается в DataTable
. Таким образом, вы не можете изменять данные в таблице.
Я думаю, что @k3b понял это правильно; установив ReadOnly = false
, вы сможете записать в таблицу данных.
foreach (System.Data.DataColumn col in tab.Columns) col.ReadOnly = false;
Ответ 2
Я продолжал получать одно и то же исключение при разных подходах. Наконец, для меня было установлено, что для свойства столбца ReadOnly значение false и изменить значение столбца Expression вместо строки [index] = "new value";
Ответ 3
В 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
С-острым
Вы даже не можете написать такой код на С#. DoNothing(ref dt.Rows[0].Item["Name"])
выдает ошибку времени компиляции.
Ответ 4
откройте файл yourdataset.xsd вашего набора данных. щелкните по таблице или объекту и щелкните по определенному столбцу, для которого необходимо изменить свойство readonly.
его простые решения.