我从CSV文件加载数据,我即时创建实体,然后将其添加到List<T>
。
以下代码采用List<T>
并将实体添加到右侧DbSet
。
public static void AddEntities<T>(List<T> entities, DbContext db) where T :class
{
using (db)
{
var set = db.Set<T>();
foreach(T e in entities)
{
set.Add(e);
}
db.SaveChanges();
}
}
我想将其更改为仅在实体不存在的情况下添加实体,否则必须更新实体。
使用Entity Framework Core实现此目标的最佳方法是什么?
我相信我应该使用System.Reflection
来:
这样的事情:
public static void AddEntities<T>(List<T> entities, DbContext db) where T :class
{
using (db)
{
var set = db.Set<T>();
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倍。
有更快的方法吗?我发现的所有代码示例均基于EF6
和ObjectContext
IObjectContextAdapter
,并且似乎此类代码不再适用于EF Core
。
答案 0 :(得分:6)
您可以使用EF Core公共(和一些内部)元数据服务来获取Find
方法所需的键值,而不是反射。要设置修改后的值,您可以使用EntityEntry.CurrentValues.SetValues
方法。
这样的事情:
using Microsoft.EntityFrameworkCore.Metadata.Internal;
public static void AddEntities<T>(List<T> entities, DbContext db) where T : class
{
using (db)
{
var set = db.Set<T>();
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();
}
}