title: Entity Framework not correctly modifying or deleting child items
body: <p>I am trying save <code>Firm</code> object that contains addresses and websites. I have developed the ability to add and remove address controls from the UI using reactive forms in Angular 7. While saving the <code>Firm</code> object, it is creating additional entries for addresses and websites and not treating it as existing record. </p>
  
  <p>So if I delete websites and addresess from the UI, I can see that I am passing the correct amount of array elements to the backend api. So I am rest assured that the issue is with Entity Framework.</p>
  
  <p>So what I am trying to achieve is that if the user deletes addresses or websites from the client side, it should update the same when calling the update method in Entity Framework. I am using Entity Framework 6</p>
  
  <p>UI - Where I can add multiple addressess</p>
  
  <p><a href="https://i.stack.imgur.com/zp1vs.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/zp1vs.png" alt="enter image description here"></a></p>
  
  <p>Here are my model classes</p>
  
  <p>NewFirmViewModel</p>
  
  <pre><code> public class NewFirmViewModel
      {
          public int FirmId { get; set; }
  
          public string FirmName { get; set;}
  
          public Nullable&lt;DateTime&gt; DateFounded { get; set; }
  
          public ICollection&lt;AddressViewModel&gt; Addresses { get; set; }
  
          public ICollection&lt;WebsiteViewModel&gt; Websites { get; set; }
  
          public bool hasIntralinks { get; set; }
      }
  </code></pre>
  
  <p>AddressViewModel        </p>
  
  <pre><code>public class AddressViewModel
  {
      public int AddressId { get; set; }
      public string Line1 { get; set; }
      public string Line2 { get; set; }
      public string Line3 { get; set; }
      public string Phone { get; set; }
      public bool IsHeadOffice { get; set; }
      public int FirmId { get; set; }
  }
  </code></pre>
  
  <p>WebsiteViewModel</p>
  
  <pre><code>public class WebsiteViewModel
  {
      private int FirmWebsiteId { get; set; }
      private string WebsiteUrl { get; set; }
      public string Username { get; set; }
      public string Password { get; set; }
      public int FirmId { get; set; }
  }
  </code></pre>
  
  <p>Entities</p>
  
  <pre><code>public class FIRM: Entity,IHasAUMs&lt;FIRM_AUM&gt; 
      {
          public FIRM()
          {
              //this.FIRM_PERSON = new HashSet&lt;FIRM_PERSON&gt;();
              this.MANAGERSTRATEGies = new HashSet&lt;MANAGERSTRATEGY&gt;();
              this.FIRM_ACTIVITY = new HashSet&lt;FIRM_ACTIVITY&gt;();
              this.FIRM_AUMs = new HashSet&lt;FIRM_AUM&gt;();
              this.FIRM_REGISTRATION = new HashSet&lt;FIRM_REGISTRATION&gt;();
              //this.ACTIVITies = new HashSet&lt;ACTIVITY&gt;();
              Addresses = new HashSet&lt;ADDRESS&gt;();
              //People = new HashSet&lt;PERSON&gt;();   
             // Websites = new HashSet&lt;FIRM_WEBSITE&gt;();
          }
  
          //public decimal ID { get; set; }
          //
          //
          //
          //
          public string NAME { get; set; }
          public string SHORT_NAME { get; set; }
          public string ALTERNATE_NAME { get; set; }
          public string WEBSITE { get; set; }
          public string WEBSITE_USERNAME { get; set; }
          public string WEBSITE_PASSWORD { get; set; }
          public bool? INTRALINKS_FIRM { get; set; }        
          public string NOTES_TEXT { get; set; }
          public string NOTES_HTML { get; set; }
          public string HISTORY_TEXT { get; set; }
          public string HISTORY_HTML { get; set; }
  
          public string HISTORY_SUM_TEXT { get; set; }
          public string HISTORY_SUM_HTML { get; set; }
  
          public Nullable&lt;decimal&gt; OLD_ORG_REF { get; set; }
          public Nullable&lt;decimal&gt; SOURCE_ID { get; set; }
  
          [DisplayFormat(DataFormatString = PermalConstants.DateFormat)]
          public Nullable&lt;DateTime&gt; DATE_FOUNDED { get; set; }
  
          public virtual  ICollection&lt;ADDRESS&gt; Addresses { get; set; }
  
        //  public ICollection&lt;FIRM_WEBSITE&gt; Websites { get; set; }
          // public ICollection&lt;PERSON&gt; People { get; set; }
  
          //public SOURCE SOURCE { get; set; }
          // public ICollection&lt;FIRM_PERSON&gt; FIRM_PERSON { get; set; }
          public ICollection&lt;MANAGERSTRATEGY&gt; MANAGERSTRATEGies { get; set; }
          public ICollection&lt;FIRM_ACTIVITY&gt; FIRM_ACTIVITY { get; set; }
          public ICollection&lt;FIRM_REGISTRATION&gt; FIRM_REGISTRATION { get; set; }
          //public ICollection&lt;ACTIVITY&gt; ACTIVITies { get; set; }
          public ICollection&lt;FIRM_WEBSITE&gt; Websites { get; set; }
  
          public Nullable&lt;int&gt; KEY_CONTACT_ID { get; set; }
          [NotMapped]
          public ICollection&lt;FIRM_AUM&gt; AUMs
          {
              get
              {
                  return this.FIRM_AUMs;
              }
          }
          public ICollection&lt;FIRM_AUM&gt; FIRM_AUMs { get; set; }
      }
  
  
      ADDRESS
  
        public class ADDRESS : Entity
      {
          public ADDRESS()
          {
              // DATE_CREATED = DateTime.Now;
          }
  
  
          public string LINE1 { get; set; }
          public string LINE2 { get; set; }
          public string LINE3 { get; set; }
          public int CITY_ID { get; set; }
          public string POSTAL_CODE { get; set; }
          public string SWITCHBOARD_INT { get; set; }
          public string NOTES { get; set; }
          public int? OLD_ADDRESS_REF { get; set; }
          public int? SOURCE_ID { get; set; }
  
          public int FIRM_ID { get; set; }
          [ForeignKey("FIRM_ID")]
          public FIRM FIRM { get; set; }
  
          [ForeignKey("CITY_ID")]
          public CITY City { get; set; }
  
          public ICollection&lt;PERSON&gt; People { get; set; }
  
          // public SOURCE SOURCE { get; set; }
  
          public bool IS_HEAD_OFFICE { get; set; }
          [NotMapped]
          public string AddressBlurb
          {
              get
              {
                  return string.Join(",", new[] { LINE1, LINE2, City != null ? City.NAME : "", City != null &amp;&amp; City.Country != null ? City.Country.NAME : "" }.Where(x =&gt; !string.IsNullOrEmpty(x)));
              }
          }
      }
  
  
      FIRM_WEBSITE
  
        public class FIRM_WEBSITE : Entity
      {
          public FIRM_WEBSITE()
          {
  
          }
          private string _WEBSITE_URL;
  
          public string WEBSITE_URL
          {
              get
              {
                  if (string.IsNullOrEmpty(_WEBSITE_URL))
                      return _WEBSITE_URL;
                  try
                  {
  
                      var ubuilder = new System.UriBuilder(_WEBSITE_URL ?? "");
  
                      return ubuilder.Uri.AbsoluteUri;
                  }
                  catch (UriFormatException ex)
                  {
                      return _WEBSITE_URL;
                  }
  
              }
              set { _WEBSITE_URL = value; }
          }
  
          public string USERNAME { get; set; }
          public string PASSWORD { get; set; }
  
  
          public int FIRM_ID { get; set; }
          [ForeignKey("FIRM_ID")]
          public FIRM FIRM { get; set; }
      }
  </code></pre>
  
  <p>API controller</p>
  
  <pre><code>  [HttpPut]
      [SkipTokenAuthorization]
      [Route("api/firm/update")]
      public IHttpActionResult Update(NewFirmViewModel model)
      {
  
  
            var firmService = GetService&lt;FIRM&gt;();
  
          if (model == null) return StatusCode(HttpStatusCode.NotFound);
  
          var firm = firmService.GetWithIncludes(model.FirmId);
  
          if (firm != null)
          {
              firm.NAME = model.FirmName;
              firm.DATE_FOUNDED = model.DateFounded;
              firm.Addresses = model.Addresses.Select(x =&gt; new ADDRESS() {ID = x.AddressId, LINE1 = x.Line1, LINE2 = x.Line2, LINE3 = x.Line3, FIRM_ID = x.FirmId}).ToList();
              firm.Websites = model.Websites.Select(x =&gt; new FIRM_WEBSITE() {ID = x.FirmWebsiteId, WEBSITE_URL = x.WebsiteUrl, USERNAME = x.Username, PASSWORD = x.Password, FIRM_ID = x.FirmId}).ToList();
  
  
              var addressIds = model.Addresses.Select(x =&gt; x.AddressId).ToList();
              var addresses = firm.Addresses.Where(x =&gt; addressIds.Contains(x.ID)).ToList(); // All of the addresses we want to associate to this firm.
              // Identify addresses to remove from this firm.
              var addressesToRemove = firm.Addresses.Where(x =&gt; !addressIds.Contains(x.ID)).ToList();
              foreach (var address in addressesToRemove)
                  firm.Addresses.Remove(address);
  
              // Identify addresses to associate to this firm.
              var existingAddressIds = firm.Addresses.Select(x =&gt; x.ID).ToList();
              var addressesToAdd = addresses.Where(x =&gt; !existingAddressIds.Contains(x.ID)).ToList();
              foreach (var address in addressesToAdd)
                  firm.Addresses.Add(address);
  
              firmService.Update(firm);
          }
          else
          {
  
          }
  
          return Ok(firm);
  }
  </code></pre>
  
  <p>DbContext</p>
  
  <pre><code>     public class Repo&lt;T&gt; : IRepo&lt;T&gt; where T : Entity, new()
          {
              public readonly Db dbContext;
  
              private ILogger _logger;
              private IQueryable&lt;T&gt; lastQuery { get; set; }
              private bool? _enablelazyloading;
              private IEntityWatcher&lt;T&gt; _watcherNotification;
              private bool _EnableChangeNotification;
              public string ID { get; set; }
              private string _clientId;
  
              #region Constructors
              public Repo(IDbContextFactory f)
              {
                  if (typeof(T).GetCustomAttribute&lt;SeparateDbContext&gt;() != null)
                      dbContext = f.GetContext&lt;T&gt;();
                  else
                      dbContext = f.GetContext();
                  _logger = IoC.Resolve&lt;ILogger&gt;();
                  try
                  {
                      _watcherNotification = IoC.Resolve&lt;IEntityWatcher&lt;T&gt;&gt;();
                  }
                  catch (Exception ex)
                  {
                      _logger.Error("Change Notification failed to resolve in Repo.  The Repo will continue to function without notification.", ex);
  
                  }
              }
              public Repo() : this(new DbContextFactory()) { }
              #endregion
  
              public bool? EnableLazyLoading
              {
                  get { return dbContext.EnableLazyLoading; }
                  set { dbContext.EnableLazyLoading = value; }
              }
  
              public void SetClientId(string clientId)
              {
                  var oc = dbContext.Database.Connection as OracleConnection;
  
                  if (oc != null)
                  {
                      oc.Open();
                      oc.ClientId = clientId;
                      oc.Close();
                  }
              }
  
  
              public T Update(T obj)
              {
                  _logger.Info("Repo.Update {0}", obj);
                  var entity = Get(obj.ID);
                  var oldEntity = new T();
                  var entry = dbContext.Entry(entity);
                  oldEntity.InjectFrom(entry.OriginalValues.ToObject());
                  if (dbContext.Entry(obj).State == System.Data.Entity.EntityState.Detached)
                  {
                      entry.CurrentValues.SetValues(obj);
                  }
                      LogAllModifiedEntities(dbContext);
                  dbContext.SaveChanges();
                  if (_watcherNotification != null)
                      _watcherNotification.EntityChanged(ChangeNotificationType.Modified, entity, oldEntity);
                  return Get(obj.ID);
              }
  
  
   public void EntityChanged(ChangeNotificationType changeNotificationType, T newEntity, T oldEntity) {
              if(_entityAuditEnabled) {
                  var filter = IoC.Resolve&lt;IEntityWatchFilter&lt;T&gt;&gt;();
                  filter.Filter(changeNotificationType, newEntity, oldEntity);
              }
          }
      }
  
     public bool Filter(ChangeNotificationType changeNotificationType, T newEntity, T oldEntity) {
              try {
                  ///only 
                  if(_WatchList.Contains(typeof(T).Name) || !_WatchList.Any()) {
                      var newLegacyStratImpl = newEntity as ILegacyStrategy;
                      var oldLegacyStratImpl = oldEntity as ILegacyStrategy;
                      var blankStrategies = IoC.Resolve&lt;ICrudService&lt;LEGACY_STRATEGY&gt;&gt;().Where(x =&gt; x.NAME.Trim() == "").Select(x =&gt; x.ID).AsEnumerable();
                      if(changeNotificationType == ChangeNotificationType.Added &amp;&amp; newLegacyStratImpl != null &amp;&amp; newLegacyStratImpl.LEGACY_STRATEGY_ID.HasValue &amp;&amp; !blankStrategies.Contains(newLegacyStratImpl.LEGACY_STRATEGY_ID.Value)) {
  
                          _action.Added(newEntity);
                          return true;
                      } else if(changeNotificationType == ChangeNotificationType.Deleted &amp;&amp; newLegacyStratImpl != null) {
                          _action.Deleted(newEntity);
                          return true;
                      } else if(changeNotificationType == ChangeNotificationType.Modified &amp;&amp; newLegacyStratImpl != null &amp;&amp; oldLegacyStratImpl != null) {
                          ///need to go the extra distance and make sure the legacy strategy was changed and not some other property.
                          var hasChanged = newLegacyStratImpl.LEGACY_STRATEGY_ID != oldLegacyStratImpl.LEGACY_STRATEGY_ID;
                          if(hasChanged) {
                              _action.Modified(newEntity, oldEntity);
                              return true;
                          } else {
                              return false;
                          }
                      }
                  }
                  return false;///all else fails...
              } catch(Exception ex) {
                  _logger.Error(ex);
                  return false;
              }
          }
  </code></pre>