实体框架核心:检查一个通用实体是否已经在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?

查看:510
本文介绍了实体框架核心:检查一个通用实体是否已经在dbset中然后添加或更新的最快方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从CSV文件加载数据,我即时创建实体,然后将它们添加到列表< T>

I load data from a CSV file, I create entities on the fly then I add them to a List<T>.

以下代码采用列表< T> ,并将实体添加到右侧 DbSet

The following code takes a List<T> and adds the entities to the right 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.

使用Entity Framework Core完成此项工作的最佳方法是什么?
我相信我应该使用 System.Reflection 来:

What is the best way to accomplish this with Entity Framework Core? I believe I should use System.Reflection to:


  • 获取至少该ID,但是最好通过密钥获取dbset的所有密钥,以查找一个实体是否已经在DbSet中。

  • 如果发现,然后使用新实体的值更新它,否则将其添加到集合

这样的东西: p>

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.

有更快的方法吗?根据 ObjectContext IObjectContextAdapter ,我发现的所有代码示例都是 EF6 / code>,似乎这种代码不再使用 EF Core

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.

推荐答案

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

Instead of reflection, you could use the EF Core public (and some internal) metadata services to get the key values needed for Find method. For setting the modified values you could use EntityEntry.CurrentValues.SetValues method.

像这样:

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

这篇关于实体框架核心:检查一个通用实体是否已经在dbset中然后添加或更新的最快方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆