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