Carico i dati da un file CSV, creo le entità al volo e le aggiungo a un List<T>
.
Il seguente codice accetta una List<T>
e aggiunge le entità a destra 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();
}
}
Mi piacerebbe cambiarlo per aggiungere l'entità solo se non esiste, altrimenti deve aggiornarlo.
Qual è il modo migliore per farlo con Entity Framework Core? Credo che dovrei usare System.Reflection
per:
Qualcosa come questo:
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();
}
}
Il codice viene eseguito da 3 a 4 volte più lento rispetto al semplice add.
C'è un modo più veloce? Tutti gli esempi di codice che sto cercando sono tutti per EF6
, basati su ObjectContext
e IObjectContextAdapter
e sembra che questo tipo di codice non funzioni più con EF Core
.
Invece di riflettere, è possibile utilizzare i servizi di metadati pubblici EF Core (e alcuni interni) per ottenere i valori chiave necessari per il metodo Find
. Per l'impostazione dei valori modificati è possibile utilizzare il metodo EntityEntry.CurrentValues.SetValues
.
Qualcosa come questo:
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();
}
}