EF’de bir üst model güncellenirken alt modeller nasıl eklenir / güncellenir silinir

Bugün .Net Core uygulama geliştirirken yaşadığım bir sorun üzerine bu makaleyi kendime not olarak ekleme gereksinimi duydum. EF kullanırken alt bağlılıkları olan modeli güncellerken alt bağlılıklarını model’de göndermediğim de silinmesini istemekteydim. Bu işlem için örnek bir kütüphane aşağıdaki şekilde yazılabilir.
Örnek Modellerim
public class UstModel
{
public UstModel()
{
this.AltModel = new List<AltModel>();
}
public int Id { get; set; }
public virtual ICollection<AltModel> AltModel { get; set; }
}
public class AltModel
{
public int Id { get; set; }
public string Adi { get; set; }
public int UstModelId { get; set; }
}
Güncelleme Method’um açıklamalarıyla aşağıdaki gibi
public void Update(UstModel model)
{
var mevcutKayit = _dbContext.UstModel
.Where(p => p.Id == model.Id)
.Include(p => p.AltModel)
.SingleOrDefault();
if (mevcutKayit != null)
{
// UstModelin değerlerini eşitle
_dbContext.Entry(mevcutKayit).CurrentValues.SetValues(model);
// Altmodeli sil
foreach (var _mevcutAltKayit in mevcutKayit.AltModel.ToList())
{
if (!model.AltModel.Any(c => c.Id == _mevcutAltKayit.Id))
_dbContext.AltModel.Remove(_mevcutAltKayit);
}
// Altmodeli Güncelle ve Ekle
foreach (var altModel in model.AltModel)
{
var _mevcutAltKayit = mevcutKayit.AltModel
.Where(c => c.Id == altModel.Id)
.SingleOrDefault();
if (_mevcutAltKayit != null)
// AltModeli Güncelle
_dbContext.Entry(_mevcutAltKayit).CurrentValues.SetValues(altModel);
else
{
// Altmodeli Ekle
var yeniAltKayit = new AltModel
{
Adi = altModel.Adi,
//...
};
mevcutKayit.AltModel.Add(yeniAltKayit);
}
}
_dbContext.SaveChanges();
}
}
Ancak biraz daha araştırdığımda şu şekilde bir method ile karşılaştım. Yukarıdaki method işime yaradığı için test etmedim ama doğru görünüyor.
protected void UpdateChildCollection<Tparent, Tid , Tchild>(Tparent dbItem, Tparent newItem, Func<Tparent, IEnumerable<Tchild>> selector, Func<Tchild, Tid> idSelector) where Tchild : class
{
var dbItems = selector(dbItem).ToList();
var newItems = selector(newItem).ToList();
if (dbItems == null && newItems == null)
return;
var original = dbItems?.ToDictionary(idSelector) ?? new Dictionary<Tid, Tchild>();
var updated = newItems?.ToDictionary(idSelector) ?? new Dictionary<Tid, Tchild>();
var toRemove = original.Where(i => !updated.ContainsKey(i.Key)).ToArray();
var removed = toRemove.Select(i => DbContext.Entry(i.Value).State = EntityState.Deleted).ToArray();
var toUpdate = original.Where(i => updated.ContainsKey(i.Key)).ToList();
toUpdate.ForEach(i => DbContext.Entry(i.Value).CurrentValues.SetValues(updated[i.Key]));
var toAdd = updated.Where(i => !original.ContainsKey(i.Key)).ToList();
toAdd.ForEach(i => DbContext.Set<Tchild>().Add(i.Value));
}
Kullanımı
UpdateChildCollection(dbCopy, detached, p => p.MyCollectionProp, collectionItem => collectionItem.Id)
Tüm bunların geniş ölçekte nasıl performans göstereceği hakkında hiçbir fikrim yok, ancak bu sorunla başka nasıl başa çıkacağımdan emin değilim.