entity framework核心:检查通用实体是否已经在dbset中然后添加或更新它的最快方法是什么?

我从CSV文件加载数据,我在运行中创建实体然后将它们添加到List

以下代码采用List并将实体添加到右侧DbSet

 public static void AddEntities(List entities, DbContext db) where T :class { using (db) { var set = db.Set(); foreach(T e in entities) { set.Add(e); } db.SaveChanges(); } } 

我想更改它只是在它不存在时添加实体,否则它必须更新它。

使用Entity Framework Core实现此目标的最佳方法是什么? 我相信我应该使用System.Reflection

  • 获得至少ID,但最好获得dbset的所有密钥
  • 循环遍历键以查找实体是否已在DbSet中
  • 如果找到,则使用新实体的值更新它,否则将其添加到集合中

像这样的东西:

 public static void AddEntities(List entities, DbContext db) where T :class { using (db) { var set = db.Set(); foreach(T e in entities) { var idProperty = e.GetType().GetProperty("ID").GetValue(e,null); var obj = set.Find(idProperty); if (obj==null) { set.Add(e); } else { var properties = (typeof(T)).GetProperties(); foreach (var p in properties) { var value = e.GetType().GetProperty(p.Name).GetValue(e,null); obj.GetType().GetProperty(p.Name).SetValue(obj,value); } } } db.SaveChanges(); } } 

代码运行速度比简单添加慢3到4倍。

有更快的方法吗? 我发现的所有代码示例都是基于ObjectContextIObjectContextAdapter ,看起来这种代码不再适用于EF Core

您可以使用EF Core公共(和一些内部)元数据服务来获取Find方法所需的键值,而不是reflection。 要设置修改后的值,可以使用EntityEntry.CurrentValues.SetValues方法。

像这样的东西:

 using Microsoft.EntityFrameworkCore.Metadata.Internal; public static void AddEntities(List entities, DbContext db) where T : class { using (db) { var set = db.Set(); var entityType = db.Model.FindEntityType(typeof(T)); var primaryKey = entityType.FindPrimaryKey(); var keyValues = new object[primaryKey.Properties.Count]; foreach (T e in entities) { for (int i = 0; i < keyValues.Length; i++) keyValues[i] = primaryKey.Properties[i].GetGetter().GetClrValue(e); var obj = set.Find(keyValues); if (obj == null) { set.Add(e); } else { db.Entry(obj).CurrentValues.SetValues(e); } } db.SaveChanges(); } }