51

最初にSqlDataAdapterオブジェクトを何度も作成した短いコードがあります。

呼び出しを少し合理化しようとして、SqlDataAdapterSqlCommandに置き換え、 SqlConnectionをループの外に移動しました。

今、DataTableに返されたデータの行を編集しようとすると、以前にスローされなかったReadOnlyExceptionがスローされます。

注: ID に基づいて従業員の氏名を取得するカスタム関数があります。ここでは簡単にするために、以下のコード例で「John Doe」を使用して要点を示しました。

ExampleQueryOldはSqlDataAdapterで動作します。ExampleQueryNewは、 DataRowの要素に書き込もうとするたびに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が舞台裏で何かを行っているためですか?

4

4 に答える 4

99

usingDataAdapter.Fillは、列が主キーかどうか、および列が読み取り専用かどうかを含むデータベース スキーマをロードしません。データベース スキーマをロードするには、 を使用しますDataAdapter.FillSchemaが、それは問題ではありません。

を使用DataReaderしてテーブルに入力すると、スキーマがロードされます。そのため、index列は読み取り専用で (おそらく主キーであるため)、その情報はDataTable. これにより、テーブル内のデータを変更できなくなります。

@k3bはそれを正しく理解したと思います。を設定ReadOnly = falseすることで、データテーブルに書き込めるようになります。

foreach (System.Data.DataColumn col in tab.Columns) col.ReadOnly = false; 
于 2011-03-27T05:51:45.260 に答える
-1

データセットの yourdataset.xsd ファイルを開きます。テーブルまたはオブジェクトをクリックし、読み取り専用プロパティを変更する必要がある特定の列をクリックします。その簡単な解決策。

于 2014-08-30T15:04:19.790 に答える