/// <summary>
        /// Copy changed values
        /// </summary>
        protected virtual IList <EntityTuple <TEntity> > ReduceToModifications <TEntity>(IList <TEntity> source) where TEntity : Entity
        {
            var entities = new List <EntityTuple <TEntity> >();

            foreach (var entity in source)
            {
                var reducedEntity = ReduceToModifications(entity);
                var tuple         = new EntityTuple <TEntity>(entity, reducedEntity);
                entities.Add(tuple);
            }

            return(entities);
        }
        /// <summary>
        /// Modifies the EntityTuple.ReducedEntity by replacing related entities with their corresponding clones from the reduced entity set
        /// </summary>
        /// <param name="entityTuple"></param>
        /// <param name="flatTransmissionSet"></param>
        protected virtual void FixupRelations(EntityTuple <Entity> entityTuple, IEnumerable <EntityTuple <Entity> > flatTransmissionSet)
        {
            Entity entity        = entityTuple.Entity;
            Entity reducedEntity = entityTuple.ReducedEntity;

            switch (reducedEntity.ChangeTracker.State)
            {
            case ObjectState.Added:
            {
                // copy navigation properties
                var navigationProperties = entity.PropertyInfos
                                           .Where(p => p.IsPhysical && p.Attributes.Any(attribute => attribute is NavigationPropertyAttribute))
                                           .Select(p => p.PropertyInfo);

                foreach (var navigationProperty in navigationProperties)
                {
                    var referencedInstance = navigationProperty.GetValue(entity, null);

                    var referencedEntityCollection = referencedInstance as ITrackableCollection;
                    if (!ReferenceEquals(null, referencedEntityCollection))
                    {
                        if (referencedEntityCollection.Count > 0)
                        {
                            var collection = navigationProperty.GetValue(reducedEntity, null) as ITrackableCollection;

                            foreach (Entity referencedEntity in referencedEntityCollection)
                            {
                                // lookup reduced version of current value (entity)
                                Entity changeSetEntity;
                                var    entry = flatTransmissionSet.FirstOrDefault(e => e.Entity.Equals(referencedEntity));
                                if (entry != null)
                                {
                                    changeSetEntity = entry.ReducedEntity;
                                }
                                else
                                {
                                    // in case of directed relation (i.e. only one entity has a relation to the other and the other entity has not relation back)
                                    // the related entity might not yet be in the change set and has to be specifically created
                                    changeSetEntity = ReduceToModifications(referencedEntity);
                                }

                                collection.Add(changeSetEntity);
                            }
                        }
                    }
                    else if (referencedInstance is Entity)
                    {
                        // lookup reduced version of current value (entity)
                        var entry = flatTransmissionSet.FirstOrDefault(e => e.Entity.Equals(referencedInstance));
                        if (entry != null)
                        {
                            navigationProperty.SetValue(reducedEntity, entry.ReducedEntity, null);
                        }
                    }
                }
            }
            break;

            case ObjectState.Unchanged:
                if (entity.HasChanges)
                {
                    // there are changes in relations
                    goto case ObjectState.Modified;
                }
                break;

            case ObjectState.Modified:
            case ObjectState.Deleted:
            {
                // copy changed navigation properties (relations and foreign keys)

                // single relation
                var physicalProperties = entity.PropertyInfos.Where(p => p.IsPhysical && p.Attributes.Any(attribute => attribute is NavigationPropertyAttribute)).ToDictionary(p => p.Name);
                foreach (var property in entity.ChangeTracker.OriginalValues.Where(p => physicalProperties.ContainsKey(p.Key)))
                {
                    if (!reducedEntity.ChangeTracker.OriginalValues.ContainsKey(property.Key))
                    {
                        // lookup reduced version of current value (entity)
                        Entity currentChangeSetEntity = null;
                        {
                            // get current value (entity)
                            var currentEntity = (Entity)entity.GetProperty(property.Key, true);
                            if (currentEntity != null)
                            {
                                var entry = flatTransmissionSet.FirstOrDefault(e => e.Entity.Equals(currentEntity));
                                if (entry != null)
                                {
                                    currentChangeSetEntity = entry.ReducedEntity;
                                }
                                else
                                {
                                    // in case of directed relation (i.e. only one entity has a relation to the other and the other entity has not relation back)
                                    // the related entity might not yet be in the change set and has to be specifically created
                                    currentChangeSetEntity = ReduceToModifications(currentEntity);
                                }
                            }
                        }

                        Entity originalChangeSetEntity = null;
                        {
                            // get current value (entity)
                            var currentEntity = (Entity)entity.ChangeTracker.OriginalValues[property.Key];
                            if (currentEntity != null)
                            {
                                var entry = flatTransmissionSet.FirstOrDefault(e => e.Entity.Equals(currentEntity));
                                if (entry != null)
                                {
                                    originalChangeSetEntity = entry.ReducedEntity;
                                }
                                else
                                {
                                    // in case of directed relation (i.e. only one entity has a relation to the other and the other entity has not relation back)
                                    // the related entity might not yet be in the change set and has to be specifically created
                                    originalChangeSetEntity = ReduceToModifications(currentEntity);
                                }
                            }
                        }

                        reducedEntity.SetProperty(property.Key, currentChangeSetEntity, true);
                        reducedEntity.ChangeTracker.OriginalValues[property.Key] = originalChangeSetEntity;
                    }
                }

                // relation added to collection
                foreach (var relation in entity.ChangeTracker.ObjectsAddedToCollectionProperties)
                {
                    var navigationProperty = reducedEntity.GetType().GetProperty(relation.Key).GetValue(reducedEntity, null) as ITrackableCollection;
                    var objectList         = new EntityList();
                    foreach (var referencedEntity in relation.Value)
                    {
                        // lookup reduced version of current value (entity)
                        Entity changeSetEntity;
                        var    entry = flatTransmissionSet.FirstOrDefault(e => e.Entity.Equals(referencedEntity));
                        if (entry != null)
                        {
                            changeSetEntity = entry.ReducedEntity;
                        }
                        else
                        {
                            // in case of directed relation (i.e. only one entity has a relation to the other and the other entity has not relation back)
                            // the related entity might not yet be in the change set and has to be specifically created
                            changeSetEntity = ReduceToModifications(referencedEntity);
                        }

                        if (changeSetEntity != null && !navigationProperty.Contains(changeSetEntity))
                        {
                            navigationProperty.Add(changeSetEntity);
                            objectList.Add(changeSetEntity);
                        }
                    }

                    if (reducedEntity.ChangeTracker.ObjectsAddedToCollectionProperties.ContainsKey(relation.Key))
                    {
                        continue;
                    }

                    reducedEntity.ChangeTracker.ObjectsAddedToCollectionProperties.Add(relation.Key, objectList);
                }

                // relation removed from collection
                foreach (var relation in entity.ChangeTracker.ObjectsRemovedFromCollectionProperties)
                {
                    var objectList = new EntityList();
                    foreach (var referencedEntity in relation.Value)
                    {
                        // lookup reduced version of current value (entity)
                        Entity changeSetEntity;
                        var    entry = flatTransmissionSet.FirstOrDefault(e => e.Entity.Equals(referencedEntity));
                        if (entry != null)
                        {
                            changeSetEntity = entry.ReducedEntity;
                        }
                        else
                        {
                            // in case of directed relation (i.e. only one entity has a relation to the other and the other entity has no relation back)
                            // the related entity might not yet be in the change set and has to be specifically created
                            changeSetEntity = ReduceToModifications(referencedEntity);
                        }

                        if (changeSetEntity != null)
                        {
                            objectList.Add(changeSetEntity);
                        }
                    }

                    reducedEntity.ChangeTracker.ObjectsRemovedFromCollectionProperties.Add(relation.Key, objectList);
                }
            }
            break;

            default:
                throw new InvalidOperationException();
            }
        }