public void Migrate(IEnumerable <LocaleResourceEntry> entries, bool updateTouchedResources = false) { Guard.ArgumentNotNull(() => entries); if (!entries.Any() || !_languages.Any()) { return; } using (var scope = new DbContextScope(_ctx, autoDetectChanges: false)) { var langMap = _languages.ToDictionarySafe(x => x.UniqueSeoCode.EmptyNull().ToLower()); var toDelete = new List <LocaleStringResource>(); var toUpdate = new List <LocaleStringResource>(); var toAdd = new List <LocaleStringResource>(); // remove all entries with invalid lang identifier var invalidEntries = entries.Where(x => x.Lang != null && !langMap.ContainsKey(x.Lang.ToLower())); if (invalidEntries.Any()) { entries = entries.Except(invalidEntries); } foreach (var lang in langMap) { foreach (var entry in entries.Where(x => x.Lang == null || langMap[x.Lang.ToLower()].Id == lang.Value.Id)) { bool isLocal; var db = GetResource(entry.Key, lang.Value.Id, toAdd, out isLocal); if (db == null && entry.Value.HasValue() && !entry.UpdateOnly) { // ADD action toAdd.Add(new LocaleStringResource { LanguageId = lang.Value.Id, ResourceName = entry.Key, ResourceValue = entry.Value }); } if (db == null) { continue; } if (entry.Value == null) { // DELETE action if (isLocal) { toAdd.Remove(db); } else { toDelete.Add(db); } } else { if (isLocal) { db.ResourceValue = entry.Value; continue; } // UPDATE action if (updateTouchedResources || !db.IsTouched.GetValueOrDefault()) { db.ResourceValue = entry.Value; toUpdate.Add(db); if (toDelete.Contains(db)) { toDelete.Remove(db); } } } } } // add new resources to context _resources.AddRange(toAdd); // remove deleted resources _resources.RemoveRange(toDelete); // update modified resources toUpdate.Each(x => _ctx.Entry(x).State = System.Data.Entity.EntityState.Modified); // save now int affectedRows = _ctx.SaveChanges(); } }