【问题标题】:Best way to get changes in a DataSet and save them to the database获取数据集中更改并将其保存到数据库的最佳方法
【发布时间】:2020-04-09 19:35:12
【问题描述】:

在使用 Npgsql 框架连接到 PostgreSQL 数据库的 C# WinForms 项目中,我需要允许用户在 DGV 中的任何位置进行更改,然后单击按钮,我需要启动一个流程来查找这些更改并提交将它们添加到数据库中。

我目前有以下代码遍历 DGV 的 DataTable,在每个 DataRow 中它遍历每一列并将 DataRowVersion 的原始值与建议值进行比较:

private void CheckDgvForChangedCells(DataTable dt)
{
    string strOriginalValue;
    string strEnteredValue;
    int intRowIndex;
    int intColumnIndex;

    for (intRowIndex = 0; intRowIndex <= dt.Rows.Count - 1; intRowIndex++)
    {
        for (intColumnIndex = 0; intColumnIndex <= dt.Columns.Count - 1; intColumnIndex++)
        {
            DataRow drCurrRow = dt.Rows[intRowIndex];
            strOriginalValue = drCurrRow[intColumnIndex, DataRowVersion.Original].ToString();
            strEnteredValue = drCurrRow[intColumnIndex, DataRowVersion.Proposed].ToString();

            if (strOriginalValue != strEnteredValue)
            {
                // Do something
            }
        }
    }
}

填充 DataTable 的数据库表目前只有 1400 多行,随着时间的推移会增加,还有 7 列,当我把这些放在一起时,我想知道这是否是查找所有数据的最佳/最有效的方法更改值并在找到每个值时更新数据库。

[更新]

根据 Steve 在 cmets 中的建议,我尝试使用 DataTable.GetChanges(),但我没有看到如何仅获取给定行中已更改的列。

我更改了三个不同行中的多个单元格,dtChanges.Rows.Count 是 3,正如预期的那样,但整行都在那里,新值在编辑的单元格中。我没有看到如何使用 dtChanges 仅使用已更改行的相应更改列来更新数据库。

【问题讨论】:

  • 为什么不DataSet.GetChanges?还是对 DataTable 使用相同的方法?
  • 但是,如果您已经通过 DataAdapter 提取了 DataSet,那么您可以简单地调用 DataAdapter.Update 方法(还需要提取主键)
  • @Steve,我稍微摆弄了一下DataTable.GetChanges,但我不知道如何确定一行中的哪些字段已更改。 dtChanges.Rows.Count 显示我更改的行数,但其中的每一行都有整行。是否期望我接受它并在行中的所有值上构建我的更新命令,或者有没有办法只获取实际更改的单元格?
  • 请考虑对数据库的调用始终是调用,即使您更新单个字段或整行也是如此。我不认为你应该在性能上有任何明显的差异。但是,当然,如果这是最重要的,那么您可以衡量差异。
  • 考虑一下,使用DataTable.GetChanges 至少可以让我只处理已更改的行。我将在这些行上构建一个更新,更新所有列 - 正如你所说,总的来说它不会有太大的不同,因为无论如何我都必须调用数据库。

标签: c# datagridview datatable datarow


【解决方案1】:

我想使用 DataTable 中的GetChanges 方法会以令人满意的方式解决您的问题。此方法返回一个仅包含更改的行的 DataTable,您可以实现一个简单的逻辑来更新您的记录。这将使您无需像现在一样检查所有 1400 行并比较每个版本值。

private void CheckDgvForChangedCells(DataTable dt)
{

    DataTable dtChanges = dt.GetChanges();
    foreach (DataRow row in dtChanges.Row)
    {
        switch(row.RowState)
        {
            case DataRowState.Modified:
                // TODO
                ExecuteUpdateCommand(row);
                break;
            case DataRowState.Added:
                // TODO
                ExecuteInsertCommand(row);
                break;
            case DataRowState.Deleted:
                // This is trickier. You cannot access any field in a deleted row
                // So you first need to call row.RejectChanges, get the primary key value
                // delete the row on the database, re-delete the row in the DataTable
                // TODO
                ExecuteDeleteCommand(row);
                break;
            }
        }
        // Do not forget to call AcceptChanges to set the table to a pristine initial editing state
        dt.AcceptChanges();
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-07
    • 2012-06-19
    • 1970-01-01
    • 1970-01-01
    • 2016-10-18
    • 2016-11-15
    • 2018-01-19
    相关资源
    最近更新 更多