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.

You may also like...