實體框架核心:檢查通用實體是否已經在dbset中然後添加或更新它的最快方法是什麼?

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倍。

有更快的方法嗎?所有代碼示例我發現都是為了EF6 ,基於ObjectContextIObjectContextAdapter ,似乎這種代碼不會再與工作EF Core

一般承認的答案

您可以使用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();
    }
}


Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow