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

时间:2017-02-27 11:52:34

标签: c# entity-framework entity-framework-core

我从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来:

  • 至少获取ID,但最好获得dbset的所有密钥
  • 循环键以查找实体是否已存在于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)
        {
            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倍。

有更快的方法吗?我发现的所有代码示例均基于EF6ObjectContext IObjectContextAdapter,并且似乎此类代码不再适用于EF Core

1 个答案:

答案 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();
    }
}