Entity Framework Core:高效的数据库更新
Posted
技术标签:
【中文标题】Entity Framework Core:高效的数据库更新【英文标题】:Entity Framework Core: efficient database update 【发布时间】:2021-10-11 12:31:25 【问题描述】:我有一个使用 Entity Framework Core 来更新数据库的 ASP.NET Core 3.1 应用程序。但我需要一些建议来了解我是否使用了更新给定表的好方法。
假设我有一个表TableState
,其中包含三列:ID
、DESCRIPTION
和STATE
(ID
是主键),下面是它的关联实体类TableState
:
public class TableState
public int ID get; set;
public string Description get; set;
public string State get; set;
鉴于TableState
对象的列表,我需要有效地更新表。
更新是特殊的,因为对于列表中的每个 TableState
对象:
ID
),我需要更新记录
如果在表中没有找到,需要插入到数据库中
最后,如果它存在于数据库中,但不在列表中,我需要将State
列更新为INACTIVE
这是我实现的算法,我想要一些反馈来了解它是否可以改进:
public void UpdateTableState (List<TableState> inputs)
var currentTableStates = Context.Set<TableSet>().ToList();
// I retrieve all records in the database
// One way to detect records to add or update
foreach (TableState input in inputs)
var foundTableState = currentTableState.FirstOrDefault(ts => ts.ID == input.Id);
// The input does not exist in DB, so it must be added
if (foundTableState == null)
Context.Set<TableSet>().Add(foundTableState);
else
foundTableState.Description = input.Description;
foundTableState.State = "Active";
// Second way to detect records to delete (set its State field to INACTIVE)
foreach (TableState currentTableState in currentTableStates )
var foundInList = inputs.FirstOrDefault(i => i.Id == currentTableState.Id);
// The input does not exist in DB, so it must be added
if (foundTableState == null)
Context.Set<TableState>.Remove(currentTableState);
如果有人找到更新表格的更好方法,请告诉我。
谢谢
【问题讨论】:
使用 vanilla EF Core 这样的操作效率很低。如果您有兴趣,我可以准备带有 EF Core 扩展的示例,它使用 MERGE 运算符来处理这种情况。 如果输入不存在,它不会在属性中包含任何 id?那么你为什么不直接插入没有id。仅供参考,如果您有成千上万的数据,将所有数据都存储到内存中将是一个问题 您好 @SvyatoslavDanyliv,感谢您抽出宝贵时间,如果可能的话,我对您的 EF Core 示例感兴趣。非常感谢 【参考方案1】:您好,感谢您的回复。
@Eldho,您的代码可能是正确的,但我还需要检测 DB 中输入集合中不存在的记录。但无论如何,谢谢你,我会尽量避免在比较之前将整个数据库表放在内存中。但我认为这是不可能的,因为:
-
如果输入中不存在 DB 中的记录:我需要将其 State 列更新为 INACTIVE
否则我需要根据其关联的输入来更新它
DB 中不存在的每个输入(它们的 ID = 0)我需要将它们添加到 DB 中。
谢谢
【讨论】:
删除此评论。这不是答案。【参考方案2】:与其将整个集合存储到内存中,不如尝试通过输入数据进行限制。
var ids = inputs.Select(x => x.Id);
var insert = inputs.Where(x=>Id==null || Id == 0).ToList() //This are data need be inserted
//This will fetch the items which exist in the table so this can be updated
var foundinTable = Context.Set<TableSet>()
.Where(x=> ids.Contains(x.Id)
.ToList();
var tobeInserted = foundIntable.Where(x> !ids.Contains(x.Id).ToList()
这减少了我们的 Dbset 以仅返回相关数据。现在你迭代它并更新它。
【讨论】:
您好,感谢您的回答,事实上,如果 ID 属性是由第三方程序预先生成的。 @J.Doe 在这种情况下,获取数据库中的记录,就像答案中的其余项目是您需要插入的一样【参考方案3】:可以通过 EF Core 扩展 linq2db.EntityFrameworkCore 完成(免责声明:我是创建者之一)
public void UpdateTableState (List<TableState> inputs)
Context.Set<TableSet>()
.Merge()
.Using(inputs)
.OnTargetKey()
.UpdateWhenMatched((t, s) => new TableState Description = s.Description, State = "Active" )
.InsertWhenNotMatched()
.UpdateWhenNotMatchedBySource(s => new TableState State = "Inactive" )
.Merge();
【讨论】:
以上是关于Entity Framework Core:高效的数据库更新的主要内容,如果未能解决你的问题,请参考以下文章
Entity Framework 7 支持批量操作和 JSON 列
Entity Framework Core 6.0 预览4 性能改进
EF6 System.Data.Entity.Core.EntityKey 在 Entity Framework Core 中的等价物是啥?