private DbSetDataManager GetSetData(Type type) { DbSetDataManager manager; if (!items.TryGetValue(type, out manager)) { manager = new DbSetDataManager(type); items.Add(type, manager); } return(manager); }
private IEnumerable <T> CloneItems <T>(DbContext context, DbSetDataManager manager, List <string> includes, bool asNoTracking) where T : class { var data = manager.Data .Select(x => (T)x.Entity) .Select(x => Clone(x, includes)) .ToDictionary(k => manager.GetId(k), v => v); foreach (var item in data) { var existing = context .ChangeTracker .Entries <T>() .ToDictionary(k => manager.GetId(k.Entity), v => v.Entity); if (existing.ContainsKey(item.Key)) { yield return(existing[item.Key]); } else { var navigationProperties = item.Value.GetType() .GetProperties() .Where(x => (x.PropertyType.IsClass || x.PropertyType.IsInterface) && x.PropertyType != typeof(string)) .ToList(); foreach (var navProperty in navigationProperties) { if (IsGenericList(navProperty.PropertyType)) { var list = navProperty.GetValue(item.Value) as IList; foreach (var listItem in list.OfType <object>().ToArray()) { var alreadyLoaded = LookupIfExistInChangeTracker <T>(context, manager, listItem, listItem.GetType()); if (alreadyLoaded != null) { list.Remove(listItem); list.Add(alreadyLoaded.Entity); } } continue; } var currentValue = navProperty.GetValue(item.Value); if (currentValue != null) { var alreadyLoaded = LookupIfExistInChangeTracker <T>(context, manager, currentValue, navProperty.PropertyType); if (alreadyLoaded != null) { navProperty.SetValue(item.Value, alreadyLoaded.Entity); } } } if (!asNoTracking) { context.Entry(item.Value).State = EntityState.Unchanged; } yield return(item.Value); } } }
private static DbEntityEntry LookupIfExistInChangeTracker <T>(DbContext context, DbSetDataManager manager, object currentValue, Type targetType) where T : class { var associatedId = manager.GetId(currentValue); var alreadyLoaded = context.ChangeTracker.Entries().FirstOrDefault(x => x.Entity.GetType() == targetType && manager.GetId(x.Entity).Equals(associatedId)); return(alreadyLoaded); }