c# - llenar - ReadOnlyException DataTable DataRow "La columna X es de solo lectura".
sqldataadapter sqlcommand (3)
El uso de DataAdapter.Fill
no carga el esquema de la base de datos, que incluye si una columna es una clave principal o no, y si una columna es de solo lectura o no. Para cargar el esquema de la base de datos, use DataAdapter.FillSchema
, pero esa no es su pregunta.
usar DataReader
para llenar una tabla carga el esquema. Por lo tanto, la columna de index
es de solo lectura (probablemente porque es la clave principal) y esa información se carga en DataTable
. Por lo tanto, le impide modificar los datos en la tabla.
Creo que @ k3b lo hizo bien; configurando ReadOnly = false
, debería poder escribir en la tabla de datos.
foreach (System.Data.DataColumn col in tab.Columns) col.ReadOnly = false;
Tengo una pequeña porción de código que originalmente creó un objeto SqlDataAdapter una y otra vez.
Tratando de optimizar mis llamadas un poco, reemplacé el SqlDataAdapter con un SqlCommand y moví el SqlConnection fuera del bucle.
Ahora, cada vez que intento editar las filas de datos devueltos a mi DataTable , aparece una ReadOnlyException que no se lanzó antes.
NOTA: Tengo una función personalizada que recupera el nombre completo del empleado en función de su ID. Para simplificar aquí, utilicé "John Doe" en mi código de ejemplo a continuación para demostrar mi punto.
ExampleQueryOld funciona con SqlDataAdapter ; ExampleQueryNew falla con ReadOnlyException cada vez que intento escribir en un elemento del DataRow :
- ExampleQueryOld
Esto funciona y no tiene problemas:
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
Este ejemplo arroja la 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;
}
¿Por qué puedo escribir en el elemento DataRow en un caso, pero no en el otro?
¿Es porque SqlConnection aún está abierto o el SqlDataAdapter está haciendo algo detrás de la escena?
Seguí recibiendo la misma excepción al intentar diferentes enfoques. Lo que finalmente funcionó para mí fue establecer la propiedad ReadOnly de la columna en false y cambiar el valor de la columna Expression en lugar de row [index] = "new value";
abra el archivo yourdataset.xsd de su conjunto de datos. haga clic en la tabla u objeto y haga clic en la columna específica que debe ser modificada de solo lectura. sus soluciones simples.