ReadOnlyException DataTable DataRow " la colonne X est en lecture seule."
j'ai un petit morceau de code qui à l'origine a créé un SqlDataAdapter objet.
en essayant de rationaliser un peu mes appels, j'ai remplacé le SqlDataAdapter avec un SqlCommand et déplacé le SqlConnection à l'extérieur de la boucle.
maintenant, chaque fois que j'essaie d'éditer des lignes de données retournées à mon DataTable, j'obtiens un ReadOnlyException jetés qui n'ont pas été jetés avant.
NOTE: j'ai une fonction personnalisée qui récupère le nom complet de l'employé en fonction de son ID. Pour simplifier, j'ai utilisé "John Doe" dans mon exemple de code ci-dessous pour démontrer mon point.
ExampleQueryOld SqlDataAdapter; ExampleQueryNew échoue avec l' ReadOnlyException chaque fois que j'essaie d'écrire sur un élément de la DataRow:
- ExampleQueryOld
Cela fonctionne et n'a pas de problèmes:
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
cet exemple lance 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;
}
Pourquoi puis-je écrire à DataRow élément dans un cas, mais pas dans l'autre?
Est-ce parce que le SqlConnection est encore ouvert ou est le SqlDataAdapter faire quelque chose derrière la scène?
3 réponses
en utilisant DataAdapter.Fill
ne charge pas le schéma de la base de données, qui comprend si une colonne est une clé primaire ou non, et si une colonne est en lecture seule ou non. Pour charger le schéma de base de données, utilisez
en utilisant DataReader
pour remplir une table charge le schéma. Ainsi, le index
la colonne est en lecture seule (probablement parce que c'est la clé primaire) et cette information est chargée dans le DataTable
. Vous empêchant ainsi de modifier les données table.
je pense que @k3b a raison; par ReadOnly = false
, vous devriez pouvoir écrire dans la table de données.
foreach (System.Data.DataColumn col in tab.Columns) col.ReadOnly = false;
j'ai continué à obtenir la même exception, tout en essayant différentes approches. Ce qui a finalement fonctionné pour moi était de mettre la propriété ReadOnly de la colonne à false et de changer la valeur de Expression colonne à la place de la rangée[index] = "nouvelle valeur";
ouvrez le votredatasset.fichier xsd de votre ensemble de données. cliquez sur le tableau ou l'objet et cliquez sur la colonne de propriété readonly besoin d'être changé. ses solutions simples.