更新 SQL 数据集合的最佳方式

Best way to update a collection of SQL data

我正在编写一个 .net/entity 框架代码片段,它应该 update/delete 一堆 MS SQL 行,其中包含从 UI 传递的最新数据。 假设 table 最初有 20 行,最新的集合包含 15 条记录。在 15 个中,9 个有变化,6 个保持不变。因此将更新 9 行,并且不在最新集合中的 5 行将从 table 中删除。 所以我的问题是,这样做的最佳方法是什么:如果我遍历所有 20 行并尝试找到它们中的每一行,它将是 O(mn)。删除所有 table 行并重新插入它们可能会更快,但我不确定。 感谢所有帮助!

所以您有一个用户界面元素,其中填充了一些 class 的项目。您还有一个 table 的数据库,其中填充了相同 class.

的项目
IEnumerable<MyClass> userInterfaceElements = ...
IQueryable<MyClass> databaseElements = ...

注意:查询还没有执行!

您希望更新数据库,以便在更新后数据库包含用户界面元素中的项目。

  • 将添加尚未在数据库中的用户界面元素
  • 需要删除不在用户界面中的数据库元素
  • 同样在数据库中的用户界面元素需要更新。

您没有写出如何确定用户界面元素是否也在数据库中。 假设您没有发明 主键。这意味着主键具有默认值(零)的元素是不在数据库中的元素。

var itemsToAdd = userInterfaceElements.Where(row => row.Id == 0);
var itemsToUpdate = userInterfaceElements.Where(row => row.Id != 0);

var idsItemsToKeep = itemsToUpdate.Select(row => row.Id);
var itemsToRemove = databaseElements.Where(row => !idsItemsToKeep.Contains(row.Id))

最后一个:删除所有具有不在您的用户界面元素中的 ID 的项目。

注意:我们还没有执行任何查询!

将项目添加到数据库会更改数据库元素,因此在进行任何更改之前,您需要具体化项目

var addList = itemsToAdd.ToList();
var updateList = itemsToUpdate.ToList();
var removeList = itemsToRemove.ToList();

到目前为止,您只查询了一次数据库:您获取了所有要删除的项目。您不能命令 entity framework 在不先获取项目的情况下删除它们。

dbContext.MyClasses.RemoveRange(removeList);
dbContext.MyClasses.AddRange(addList);

要在 entity framework 中更新,正确的方法是获取数据然后更改属性。

有些人喜欢将项目附加到 dbContext 的更改跟踪器并告诉它已更改。但是,如果其他人更改了这些项目的某些属性,尤其是当您没有在用户界面元素中显示这些值时,这可能很危险。因此,仅当您确实有一长串要更新的项目时才这样做。

正确的方法:

foreach(var itemToUpdate in updateList)
{
     var fetchedItem = dbContext.MyClasses.Find(itemToUpdate.Id);
     // TODO: update changed properties of the fetchedItem with values from itemToUpdate
}

危险的方法:

foreach(var itemToUpdate in updateList)
{
    dbContext.Entry(itemToUpdate).State = entityState.Modified;
}

最后:

dbContext.SaveChanges();

改进了删除方法

当您用数据库值填充用户界面元素时遇到问题,而其他一些进程从您的数据库中删除了其中一个值。

当您的代码查看主键时,它会认为它在数据库中,但它已经不存在了。如何处理这个元素?重新添加?就好像用户也想删除它一样?

为了解决这类问题,人们通常不会从他们的数据库中删除项目,而是声明它们已过时。他们向 table 添加了一个布尔值列,指示该项目是否要在不久的将来删除。这解决了人们想要更新项目而其他人想要删除项目的问题。

定期地,大约每个月,都会启动一个过程来删除所有过时的对象。您想要更新过时对象的可能性要低得多。

如果这需要完整保存:不要记住布尔值已过时,但要记住过时日期。定期删除所有过时时间较长的项目。

过时的好处是,如果有人不小心宣布某个项目已过时,还有一些时间来修复它。