2011-12-07 49 views
3

尝试使用Update()方法在我的数据库时,会出现DBConcurrencyException问题。我有一个具有自动递增的ID列的数据库中的表,并在我的C#程序数据表,从该表中(包括当我使用MissingSchemaAction = MissingSchemaAction.AddWithKey自动增量部分)来获取信息。DataTable的同步功能自动增量列使用数据库

如果我创建行并将其添加到数据表,数据表自动填写自动增量ID列(其中启动数据库表不放过)对我来说,这是很好的。但是,如果我删除刚刚添加的行(不先使用Update())并添加新行,则数据表autoincrement列将填充一个基于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()时,数据库期望4是下一个自动增量值,而是变为5.所以我得到错误。当用户点击一个“保存”按钮时,会发生Update(),所以理想情况下,我希望他们能够在最终保存前做出如上所示的大量更改,但是保持并发性的唯一方法是使用Update( )每行添加/删除后?

+0

哪个数据库? –

+0

MySQL数据库,对不起,我没有提到的是,更新()是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 

你找出最后一个是什么。

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

对不起,我一直没在这里都清楚,问题是,我在我的C#程序(数据表)的数据库表的内存版本使用和数据表自动增量列失控同步与数据库自动增量柱。 – NikonTC

0

我首先想到的会是你应该只处理一个行要被删除的情况下,并首先更新它,然后将其删除,以保持自动递增的ID同步。

但是,我遇到了这种情况,它似乎是由我的DataGridView托管在第三方控件引起的。特别是,当用户在DataGridView的“新”行中有焦点时,切换到另一个应用程序,然后单击回到DataGridView。此时新行原来的DataRow实例被删除,新的一个是用递增的ID值创建。我一直没能想出一个办法来处理它实际上是删除之前的行删除,我也不能找出第三方控制做触发此。

因此,就目前而言,我在一个非常严厉的方式处理这个问题,通过从数据库中查询正确的自动增加值的修正新的数据行,如果必要的。如果一切都失败了,这个解决方案似乎工作。 (注意我使用的是SqlCe而不是MySQL)

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; 
       } 
      } 
     } 
    } 
}