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);
        }