/// <summary> /// Updates a collection, adding/removing values. The entities in the collection are assumed to be attached/tracked. /// newValues need not already exist. /// Also updates the fields of each element. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="collection"></param> /// <param name="newValues"></param> /// <param name="context"></param> public static void UpdateCollectionAndElements <T>(this ICollection <T> collection, IEnumerable <T> newValues, IMyDbContext context) where T : class, IEntity { //remove those that need to be removed var toRemove = collection.Where(x => !newValues.Any(y => y.ID == x.ID)).ToList(); foreach (T item in toRemove) { context.SetEntryState(item, EntityState.Deleted); } //find the ones that overlap and add or update them foreach (T item in newValues) { if (item.ID == 0) //this means it's newly added { collection.Add(item); } else //this is an existing entity, update it { var attached = collection.FirstOrDefault(x => x.ID == item.ID); //no need for Entry()/Attach() - these are already in the ObjectStateManager if (attached == null) { continue; //if the collection on the server has been changed and the client tries to update a deleted element, you can end up in this scenario...just skip it } context.UpdateEntryValues(attached, item); } } }