简体   繁体   English

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

[英]Entity Framework Core: What is the fastest way to check if a generic entity is already in the dbset and then add or update it?

I load data from a CSV file, I create entities on the fly then I add them to a List<T> . 我从CSV文件加载数据,即时创建实体,然后将它们添加到List<T>

The following code takes a List<T> and adds the entities to the right DbSet . 以下代码采用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();
     }
}

I'd like to change it to add the entity only if it doesn't exist, otherwise it has to update it. 我想将其更改为仅在不存在时才添加实体,否则必须更新它。

What is the best way to accomplish this with Entity Framework Core? 使用Entity Framework Core实现此目标的最佳方法是什么? I believe I should use System.Reflection to: 我相信我应该使用System.Reflection来:

  • get at least the ID but it would be better to get all the keys for the dbset 至少获取ID,但最好获取dbset的所有密钥
  • loop through the keys to find if an entity is already in the DbSet 遍历键以查找实体是否已存在于DbSet中
  • if found then update it with the values from the new entity otherwise add it to the set 如果找到,则使用新实体中的值对其进行更新,否则将其添加到集合中

Something like this: 像这样:

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

The code runs from 3 to 4 times slower than the simple add. 该代码的运行速度比简单添加的速度慢3到4倍。

Is there a faster way? 有没有更快的方法? All the code examples I am finding are all for EF6 , based on ObjectContext and IObjectContextAdapter and it seems this kind of code do not longer work with EF Core . 我发现的所有代码示例都是针对EF6 ,都是基于ObjectContextIObjectContextAdapter ,似乎这种代码不再可以与EF Core

Instead of reflection, you could use the EF Core public (and some internal) metadata services to get the key values needed for Find method. 取而代之的反射,你可以使用EF核心公共(和一些内部)元数据服务,以获得所需的键值Find方法。 For setting the modified values you could use EntityEntry.CurrentValues.SetValues method. 要设置修改后的值,可以使用EntityEntry.CurrentValues.SetValues方法。

Something like this: 像这样:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM