C# DataGridView中唯一的bool检查,更新数据库

C# DataGridView中唯一的bool检查,更新数据库,c#,sql-server,winforms,C#,Sql Server,Winforms,我有一个DataGridView,其中有一列显示为复选框。列的名称为“IsDefault”,这意味着如果选中此单元格,则应取消选中DataTable中此列中的所有其他单元格(此列中仅允许1个单元格为默认单元格) 我通过处理DataGridView的CellContentClick事件中的更改,成功地实现了这种行为,即: private void ViewIconsDataGrid_CellContentClick(object sender, DataGridViewCellEventArgs

我有一个DataGridView,其中有一列显示为复选框。列的名称为“IsDefault”,这意味着如果选中此单元格,则应取消选中DataTable中此列中的所有其他单元格(此列中仅允许1个单元格为默认单元格)

我通过处理DataGridView的CellContentClick事件中的更改,成功地实现了这种行为,即:

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事件。除了切换复选框之外,它似乎什么也不做。