C# DataGridView中唯一的bool检查,更新数据库
我有一个DataGridView,其中有一列显示为复选框。列的名称为“IsDefault”,这意味着如果选中此单元格,则应取消选中DataTable中此列中的所有其他单元格(此列中仅允许1个单元格为默认单元格) 我通过处理DataGridView的CellContentClick事件中的更改,成功地实现了这种行为,即:C# DataGridView中唯一的bool检查,更新数据库,c#,sql-server,winforms,C#,Sql Server,Winforms,我有一个DataGridView,其中有一列显示为复选框。列的名称为“IsDefault”,这意味着如果选中此单元格,则应取消选中DataTable中此列中的所有其他单元格(此列中仅允许1个单元格为默认单元格) 我通过处理DataGridView的CellContentClick事件中的更改,成功地实现了这种行为,即: private void ViewIconsDataGrid_CellContentClick(object sender, DataGridViewCellEventArgs
private void ViewIconsDataGrid_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex == -1 || e.ColumnIndex == -1)
return;
DataTable table = ViewIconsDataGrid.DataSource as DataTable;
DataGridViewCell cell = ViewIconsDataGrid.Rows[e.RowIndex].Cells[e.ColumnIndex];
Guid rowID = (Guid)ViewIconsDataGrid.Rows[e.RowIndex].Cells["ID"].Value;
if (cell.GetType() == typeof(DataGridViewCheckBoxCell))
{
DataGridViewCheckBoxCell checkBoxCell = cell as DataGridViewCheckBoxCell;
bool value = (bool)checkBoxCell.EditedFormattedValue, previous = (bool)checkBoxCell.Value;
if (value != previous)
{
if (value == true)
{
Guid currentDefault;
if(MyIcons.Defaults.TryGetValue(MyGroupID, out currentDefault))
{
DataRow [] rows = table.Select("ID = '" + currentDefault.ToString() + "'");
if(rows.Length == 1)
{
rows[0]["IsDefault"] = false;
}
}
}
ViewIconsDataGrid.EndEdit(); table.AcceptChanges();
}
}
}
现在,很明显,我正在尝试对同一数据表中的两条记录进行更改。首先,我希望DataGridView发生更改(当用户更改复选框的状态时),然后我在DataTable上做另一个更改,取消选中已选中的行,希望这将传播到DataGridView。当然,我需要将这两个更改提交到数据库
这是我的数据库“更新”代码,这是一种通用代码,也就是说,我为整个表和要更新的数据表传入一个select查询:
using (SqlConnection connection = new SqlConnection(ConfigurationManager.AppSettings["Connection"]))
{
connection.Open();
using (SqlDataAdapter adapter = new SqlDataAdapter(MyQuery, connection))
{
adapter.InsertCommand = new SqlCommandBuilder(adapter).GetInsertCommand();
adapter.DeleteCommand = new SqlCommandBuilder(adapter).GetDeleteCommand();
adapter.UpdateCommand = new SqlCommandBuilder(adapter).GetUpdateCommand();
adapter.Update(MyTable);
}
}
因此,问题是,在进行这些更改后尝试更新表时出现异常:“并发冲突:UpdateCommand影响了预期的1条记录中的0条。”。如果没有现有的默认值,则只更新一条记录,一切正常
有谁能发现我的错误,或者为我找到一个更简单的方法
编辑1:在上面的片段中,MyQuery如下所示:
@"SELECT * From Picture WHERE ID_Group = '{0}' AND Deleted = 0 ORDER BY Created DESC
{0}是我正在更新的图片组的guid,即select查询提供图片表中属于该组的所有记录。调用将表中每一行的guid更改为Unchanged。对DataAdatper.Update(表)的后续调用未找到任何要更新/插入或删除的内容 您需要在用户输入时调用更新(如单击保存按钮) 编辑以@Robinson的以下发现完成此答案
您可以为处理
CurrentCellDirtyStateChanged
事件的表引发RowChanged
事件,并手动提交DataGridView上的编辑。否则,当行失去焦点时,将引发RowChanged事件。这里有两个问题:
首先,DataGridView事件无法正确发送以缓存更改,您必须使用另一个事件,如单击按钮来强制DataGridView缓存更改
另一个问题“并发冲突”是由在具有标识列(通常是主键)的表中插入新行引起的。我建议使用另一个按钮进行插入并在DataGridView中强制输入新的标识值
更新时,我建议先进行删除,然后再进行更新:
// First process deletes.
da.Update(dt.Select(null, null, DataViewRowState.Deleted));
// Next process updates.
da.Update(dt.Select(null, null, DataViewRowState.ModifiedCurrent));
为什么要调用
table.AcceptChanges()
?此表是否与update命令中使用的表相同?请显示实际的update查询。当你说要用整个表的选择查询更新数据库时,你是不是说错了?我想,为了实例化SqlDataAdapter,我必须传入一个查询。。。我将使用我使用的查询进行更新。是的,Steve。如果我不调用AcceptChanges,我就永远不会从基础DataTable中获得RowChanged事件,因此我不知道启动执行更新的线程。此外,如果IsDefault列未绑定,并且您保留一个单独的表,其中有一行,其中包含主表中默认行的id,则可能会更容易。然后,您可以简单地覆盖辅助表中的id值,而不必从主表的一行中删除默认标志并将其重新应用到另一行。正如我对上一个答案所说(似乎已被删除),除非调用AcceptChanges,否则我不知道表何时更新。RowChanged事件根本不会触发,我使用它来知道何时启动执行实际更新的线程。第二,当我只是修改一行时(当我没有将其他行设置为false的代码时),它似乎可以工作。您能尝试在没有AcceptChanges的情况下调用更新吗?我只是想排除这种可能性。另外,我也试过这个例子。RowChanged事件是通过其参数Action=Commit响应AcceptChanges而引发的,但是当您添加新行(Action=add)和更改行字段(Action=change)时,您也会得到RowChanged事件。根据Steve的评论,请参阅我对上述伪并发冲突错误的评论。发生的情况是,在单击后的第一次更新之后,您对dataAdapter说不再有“脏”行,因此零行需要更新,因此当您调用update命令时,受影响的行数=0,因此引发(虚假)并发错误。好的,我不理解DataGridView。单击复选框打开/关闭时,我不会获取RowChanged事件。除了切换复选框之外,它似乎什么也不做。