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倍。
有更快的方法吗? 我发现的所有代码示例都是基于ObjectContext
和IObjectContextAdapter
,看起来这种代码不再适用于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(); } }