2011-12-07 6 views
3

データベースでUpdate()メソッドを使用しようとすると、DBConcurrencyExceptionの問題が発生します。私は自動増分ID列を持つデータベースにテーブルがあり、DataTableは、このテーブル(私はMissingSchemaAction = MissingSchemaAction.AddWithKeyを使用すると自動増分部分を含む)から情報を取得するC#プログラムです。DataTableの自動インクリメント列をデータベースと同期する

行を作成してデータテーブルに追加した場合、データテーブルは自動増分されたID列(データベーステーブルが途切れたところから開始)を自動的に埋め込みます。これは問題ありません。しかし、私が追加したばかりの行を(最初にUpdate()を使用せずに)削除し、新しいものを追加すると、データテーブルの自動インクリメント列には、データベースが存在しない場所のDATATABLEの値に基づいて値が設定されます。並行性エラー。例えば

:私は名前の値を持つ新しい行を追加するときにデータテーブルにコピーされます

1 Apple 
2 Orange 
3 Pear 

は、その「ぶどう」私が手:

データベース内のテーブルには、これらのレコードを持っています:結構です

1 Apple 
2 Orange 
3 Pear 
4 Grape 

が、しかし、update()メソッドを実行しない場合は、と私はブドウの行を削除し、新しい行「メロン」を追加私が取得:

1 Apple 
2 Orange 
3 Pear 
5 Melon 

私はUpdate()を実行しようとすると、データベースは次の自動インクリメントされた値になることを期待していますが、代わりに5が発生しています。 Update()は、ユーザーが「保存」ボタンをクリックしたときに発生するので、最終的に保存する前に上に示したように多くの変更を加えることが理想的ですが、Updateを使用するための並行性を保持する唯一の方法です)各行が追加/削除された後

+0

どのデータベースですか? –

+0

MySQLデータベース、申し訳ありませんが、私は言及していない、Update()は、データベースから情報を取得するために使用されるDataAdapterのメソッドです。 – NikonTC

答えて

0

期待値は5です。何か作業を行うたびに、データベースが列の穴を埋めるのは非常に非効率的です。 auto_incrementが使用されると、それは永遠に失われます。

これは常に、カラムが十分に大きいことを確認してすべてのレコードを保持するためです。たとえば、TINYINTを使用した場合は、テーブルに127レコードしか置くことができません。

自動インクリメントはテーブルレベルで保存され、Mysqlはそれが下位になる可能性があるかどうかを確認することはありません。手動で次の操作を行って、それを変更することができます。

ALTER TABLE tablename AUTO_INCREMENT=2; 

しかし、あなたがこれを行うと、道の衝突がある場合 - 悪い事が起こるしようとしています。

またはあなたはそれが

SHOW CREATE TABLE tablename; 
CREATE TABLE `tablename` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
`cat_id` int(10) unsigned NOT NULL, 
`status` int(10) unsigned NOT NULL, 
`date_added` datetime DEFAULT NULL, 
PRIMARY KEY (`id`), 
KEY `categories_list_INX` (`cat_id`,`status`), 
KEY `cat_list_INX` (`date_added`,`cat_id`,`status`) 
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1 

が何であるかを調べることができますし、最後の1が何であるかを見つけます。

SELECT LAST_INSERT_ID(); 
+------------------+ 
| LAST_INSERT_ID() | 
+------------------+ 
|    2 | 
+------------------+ 
1 row in set (0.00 sec) 
+0

申し訳ありませんが、私はC#プログラム(DataTable)でデータベーステーブルのメモリ内バージョンを使用しており、DataTableの自動インクリメント列がデータベースの自動インクリメントと同期しないカラム。 – NikonTC

0

私が最初に考えたのは、あなただけの同期で自動インクリメントIDを維持するために、それを削除し、その後、行が削除されているケースを処理し、それを最初に更新する必要があることだったでしょう。

しかし、私はこの同じ状況に遭遇しました。これは、私のDataGridViewがホストされているサードパーティのコントロールによって引き起こされたようです。具体的には、ユーザーがDataGridViewの「新しい」行にフォーカスし、別のアプリケーションに切り替えてから、DataGridViewに再度クリックします。この時点で、新しい行の元のDataRowインスタンスが削除され、ID値が増加した新しい行が作成されます。私は実際に削除される前に行の削除を処理する方法を見つけ出すことができていないし、サードパーティのコントロールがこれを引き起こしていることを把握することもできない。

したがって、私はこの問題を非常に重い手で扱います。データベースから正しい自動インクリメント値を照会し、必要に応じて新しいDataRowsを修正します。他のすべてが失敗した場合、この解決策はうまくいくと思われます。 (注:私はMySQLの代わりにSqlCeを使用しています)

void OnLoad() 
{ 
    base.OnLoad(e); 
    ... 
    _dataTable.TableNewRow += HandleTableNewRow; 
} 

void HandleTableNewRow(object sender, DataTableNewRowEventArgs e) 
{ 
    SetAutoIncrementValues(e.Row); 
} 

void SetAutoIncrementValues(DataRow row) 
{ 
    foreach (DataColumn dataColumn in _dataTable.Columns 
     .OfType<DataColumn>() 
     .Where(column => column.AutoIncrement)) 
    { 
     using (SqlCeCommand sqlcmd = new SqlCeCommand(
      "SELECT AUTOINC_NEXT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '" + 
      Name + "' AND COLUMN_NAME = '" + dataColumn.ColumnName + "'", _connection)) 
     using (SqlCeResultSet queryResult = 
      sqlcmd.ExecuteResultSet(ResultSetOptions.Scrollable)) 
     { 
      if (queryResult.ReadFirst()) 
      { 
       var nextValue = Convert.ChangeType(queryResult.GetValue(0), dataColumn.DataType); 

       if (!nextValue.Equals(row[dataColumn.Ordinal])) 
       { 
        // Since an auto-increment column is going to be read-only, apply 
        // the new auto-increment value via a separate array variable. 
        object[] rowData = row.ItemArray; 
        rowData[dataColumn.Ordinal] = nextValue; 
        row.ItemArray = rowData; 
       } 
      } 
     } 
    } 
} 
関連する問題