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

时间:2019-01-19 23:41:56

标签: c# sql .net entity-framework relational-database

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

1 个答案:

答案 0 :(得分:1)

因此,您有一个用户界面元素,其中填充了某些类的项目。您还拥有一个数据库,该数据库的表中填充了相同类的项目。

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不在您的用户界面元素中的所有项目。

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

将项目添加到数据库将更改databaseElements,因此在进行任何更改之前,需要具体化这些项目

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

现在,您已经查询数据库一次:您已提取所有要删除的项目。您不能命令实体框架删除项而不先获取它们。

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

要在实体框架中进行更新,正确的方法是获取数据,然后更改属性。

有些人喜欢将项目附加到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();

改进的删除方法

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

当您的代码查看主键时,它将认为它在数据库中,但是现在不存在了。该元素怎么办?再次添加?好像用户也希望删除它一样?

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

通常,每个月左右都会启动一个过程,以删除所有过时的对象。您想要更新过时的对象的机会要低得多。

如果需要完全保存,请执行以下操作:不记得布尔型已过时,而是已过时的日期。定期删除所有较长时间过时的项目。

关于过时的一件好事是,如果有人意外宣布某件物品过时,那么仍然有一些时间来修复它。