protected void WriteChangeContainer(IChangeContainer changeContainer, IWriter writer, IncrementalMergeState incrementalState) { IObjRef objRef = changeContainer.Reference; writer.WriteStartElement("Entity"); writer.WriteAttribute("type", objRef.RealType.FullName); writer.WriteAttribute("id", ConversionHelper.ConvertValueToType <String>(objRef.Id)); if (objRef.Version != null) { writer.WriteAttribute("version", ConversionHelper.ConvertValueToType <String>(objRef.Version)); } StateEntry stateEntry = incrementalState.objRefToStateMap.Get(objRef); if (stateEntry == null) { throw new Exception(); } writer.WriteAttribute("idx", stateEntry.index); if (changeContainer is DeleteContainer) { writer.WriteEndElement(); return; } ICreateOrUpdateContainer createOrUpdate = (ICreateOrUpdateContainer)changeContainer; WritePUIs(createOrUpdate.GetFullPUIs(), writer); WriteRUIs(createOrUpdate.GetFullRUIs(), writer, incrementalState); writer.WriteCloseElement("Entity"); }
public void SetLeftContainer(IChangeContainer leftContainer) { if (leftContainer != null && containerBuild != null) { throw new Exception(); } this.leftContainer = leftContainer; }
public void ProcessRead(IPostProcessReader reader) { reader.NextTag(); ICommandTypeRegistry commandTypeRegistry = reader.CommandTypeRegistry; ICommandTypeExtendable commandTypeExtendable = reader.CommandTypeExtendable; commandTypeExtendable.RegisterOverridingCommandType(typeof(MergeArraySetterCommand), typeof(ArraySetterCommand)); Object result = reader.ReadObject(); commandTypeExtendable.UnregisterOverridingCommandType(typeof(MergeArraySetterCommand), typeof(ArraySetterCommand)); if (!(result is CUDResult)) { throw new Exception("Can only handle results of type '" + typeof(CUDResult).Name + "'. Result of type '" + result.GetType().Name + "' given."); } ICommandBuilder commandBuilder = CommandBuilder; Member directObjRefDirectMember = this.directObjRefDirectMember; CUDResult cudResult = (CUDResult)result; IList <IChangeContainer> changes = cudResult.AllChanges; for (int i = 0, size = changes.Count; i < size; i++) { IChangeContainer changeContainer = changes[i]; if (!(changeContainer is CreateContainer)) { continue; } IObjRef ori = changeContainer.Reference; if (ori == null) { continue; } else if (ori is DirectObjRef) { IObjectFuture objectFuture = new ObjRefFuture(ori); IObjectCommand setterCommand = commandBuilder.Build(commandTypeRegistry, objectFuture, ori, directObjRefDirectMember); reader.AddObjectCommand(setterCommand); IObjectCommand mergeCommand = commandBuilder.Build(commandTypeRegistry, objectFuture, changeContainer); reader.AddObjectCommand(mergeCommand); } else { throw new Exception("Not implemented yet"); } } }
protected IChangeContainer FillClonedChangeContainer(IChangeContainer original, IdentityHashMap <IChangeContainer, IChangeContainer> alreadyClonedMap) { IChangeContainer clone = alreadyClonedMap.Get(original); if (clone is CreateContainer) { ((CreateContainer)clone).Primitives = ClonePrimitives(((CreateContainer)original).Primitives); ((CreateContainer)clone).Relations = CloneRelations(((CreateContainer)original).Relations); } else if (clone is UpdateContainer) { ((UpdateContainer)clone).Primitives = ClonePrimitives(((UpdateContainer)original).Primitives); ((UpdateContainer)clone).Relations = CloneRelations(((UpdateContainer)original).Relations); } ((AbstractChangeContainer)clone).Reference = CloneObjRef(original.Reference, true); return(clone); }
protected IMap <Type, IList <IChangeContainer> > BucketSortChanges(IList <IChangeContainer> allChanges) { HashMap <Type, IList <IChangeContainer> > sortedChanges = new HashMap <Type, IList <IChangeContainer> >(); for (int i = allChanges.Count; i-- > 0;) { IChangeContainer changeContainer = allChanges[i]; IObjRef objRef = changeContainer.Reference; Type type = objRef.RealType; IList <IChangeContainer> changeContainers = sortedChanges.Get(type); if (changeContainers == null) { changeContainers = new List <IChangeContainer>(); sortedChanges.Put(type, changeContainers); } changeContainers.Add(changeContainer); } return(sortedChanges); }
protected IList <Object> GetAllExistingObjectsFromCache(ICache cache, IList <IChangeContainer> allChanges) { List <IObjRef> existingObjRefs = new List <IObjRef>(allChanges.Count); for (int a = 0, size = allChanges.Count; a < size; a++) { IChangeContainer changeContainer = allChanges[a]; if (changeContainer is CreateContainer) { existingObjRefs.Add(null); continue; } if (changeContainer.Reference is IDirectObjRef) { throw new Exception(); } existingObjRefs.Add(changeContainer.Reference); } return(cache.GetObjects(existingObjRefs, CacheDirective.ReturnMisses)); }
protected void WriteCUDResult(ICUDResult cudResult, IWriter writer, IncrementalMergeState state) { IList <IChangeContainer> allChanges = cudResult.AllChanges; List <CreateContainer> creates = new List <CreateContainer>(); List <UpdateContainer> updates = new List <UpdateContainer>(); List <DeleteContainer> deletes = new List <DeleteContainer>(); for (int a = allChanges.Count; a-- > 0;) { IChangeContainer changeContainer = allChanges[a]; if (changeContainer is CreateContainer) { creates.Add((CreateContainer)changeContainer); } else if (changeContainer is UpdateContainer) { updates.Add((UpdateContainer)changeContainer); } else { deletes.Add((DeleteContainer)changeContainer); } } creates.Sort(createContainerComparator); updates.Sort(updateContainerComparator); deletes.Sort(deleteContainerComparator); writer.WriteStartElement("CUDResult"); writer.WriteAttribute("size", allChanges.Count); writer.WriteAttribute("creates", creates.Count); writer.WriteAttribute("updates", updates.Count); writer.WriteAttribute("deletes", deletes.Count); writer.WriteStartElementEnd(); WriteChangeContainers(creates, writer, "Creates", state); WriteChangeContainers(updates, writer, "Updates", state); WriteChangeContainers(deletes, writer, "Deletes", state); writer.WriteCloseElement("CUDResult"); }
public IList <IChangeContainer> GetChanges(Type type) { if (typeToModDict != null) { return(DictionaryExtension.ValueOrDefault(typeToModDict, type)); } typeToModDict = new Dictionary <Type, IList <IChangeContainer> >(); for (int a = AllChanges.Count; a-- > 0;) { IChangeContainer changeContainer = AllChanges[a]; Type realType = changeContainer.Reference.RealType; IList <IChangeContainer> modList = DictionaryExtension.ValueOrDefault(typeToModDict, realType); if (modList == null) { modList = new List <IChangeContainer>(); typeToModDict.Add(realType, modList); } modList.Add(changeContainer); } return(DictionaryExtension.ValueOrDefault(typeToModDict, type)); }
public ICUDResult DiffCUDResult(ICUDResult left, ICUDResult right) { CUDResultDiff diff = new CUDResultDiff(left, right, true, CudResultHelper, EntityMetaDataProvider); EqualsCUDResult(diff); if (!diff.HasChanges()) { return(null); // null means empty diff } IList <IChangeContainer> diffChanges = diff.diffChanges; for (int a = diffChanges.Count; a-- > 0;) { IChangeContainer changeContainer = diffChanges[a]; if (!(changeContainer is CreateOrUpdateContainerBuild)) { continue; } diffChanges[a] = ((CreateOrUpdateContainerBuild)changeContainer).Build(); } return(new CUDResult(diffChanges, diff.originalRefs)); }
protected IList <MergeOperation> CreateMergeOperationSequence(IMap <Type, IList <IChangeContainer> > sortedChanges) { Type[] entityPersistOrder = EntityMetaDataProvider.GetEntityPersistOrder(); IList <MergeOperation> mergeOperations = new List <MergeOperation>(); if (entityPersistOrder != null) { for (int a = entityPersistOrder.Length; a-- > 0;) { Type orderedEntityType = entityPersistOrder[a]; IList <IChangeContainer> changes = sortedChanges.Get(orderedEntityType); if (changes == null) { // No changes of current type found. Nothing to do here continue; } List <IChangeContainer> removes = new List <IChangeContainer>(changes.Count); List <IChangeContainer> insertsAndUpdates = new List <IChangeContainer>(changes.Count); for (int b = changes.Count; b-- > 0;) { IChangeContainer change = changes[b]; if (change is DeleteContainer) { removes.Add(change); } else { insertsAndUpdates.Add(change); } } if (removes.Count == 0) { // Nothing to do. Ordering is not necessary here continue; } if (insertsAndUpdates.Count == 0) { sortedChanges.Remove(orderedEntityType); } else { sortedChanges.Put(orderedEntityType, insertsAndUpdates); } IMergeServiceExtension mergeServiceExtension = GetServiceForType(orderedEntityType); MergeOperation mergeOperation = new MergeOperation(); mergeOperation.MergeServiceExtension = mergeServiceExtension; mergeOperation.ChangeContainer = removes; mergeOperations.Add(mergeOperation); } for (int a = 0, size = entityPersistOrder.Length; a < size; a++) { Type orderedEntityType = entityPersistOrder[a]; IList <IChangeContainer> changes = sortedChanges.Get(orderedEntityType); if (changes == null) { // No changes of current type found. Nothing to do here continue; } bool containsNew = false; for (int b = changes.Count; b-- > 0;) { if (changes[b].Reference.Id == null) { containsNew = true; break; } } if (!containsNew) { // Nothing to do. Ordering is not necessary here continue; } // Remove batch of changes where at least 1 new entity occured and // this type of entity has to be inserted in a global order sortedChanges.Remove(orderedEntityType); IMergeServiceExtension mergeServiceExtension = GetServiceForType(orderedEntityType); MergeOperation mergeOperation = new MergeOperation(); mergeOperation.MergeServiceExtension = mergeServiceExtension; mergeOperation.ChangeContainer = changes; mergeOperations.Add(mergeOperation); } } // Everything which is left in the sortedChanges map can be merged without global order, so batch together as much as possible foreach (Entry <Type, IList <IChangeContainer> > entry in sortedChanges) { Type type = entry.Key; IList <IChangeContainer> unorderedChanges = entry.Value; IMergeServiceExtension mergeServiceExtension = GetServiceForType(type); if (mergeServiceExtension == null) { throw new Exception("No extension found to merge entities of type '" + type.FullName + "'"); } bool cont = false; foreach (MergeOperation existingMergeOperation in mergeOperations) { if (Object.ReferenceEquals(existingMergeOperation.MergeServiceExtension, mergeServiceExtension)) { IList <IChangeContainer> orderedChanges = existingMergeOperation.ChangeContainer; for (int b = unorderedChanges.Count; b-- > 0;) { orderedChanges.Add(unorderedChanges[b]); } cont = true; break; } } if (cont) { continue; } MergeOperation mergeOperation = new MergeOperation(); mergeOperation.MergeServiceExtension = mergeServiceExtension; mergeOperation.ChangeContainer = unorderedChanges; mergeOperations.Add(mergeOperation); } ; return(mergeOperations); }
protected ICUDResult ApplyIntern(ICUDResult cudResult, bool checkBaseState, IncrementalMergeState incrementalState) { ICache stateCache = incrementalState.GetStateCache(); IList <IChangeContainer> allChanges = cudResult.AllChanges; IList <Object> originalRefs = cudResult.GetOriginalRefs(); IList <Object> allObjects = GetAllExistingObjectsFromCache(stateCache, allChanges); List <Object> hardRefs = new List <Object>(); hardRefs.Add(allObjects); // add list as item intended. adding each item of the source is NOT needed List <IObjRef> toFetchFromCache = new List <IObjRef>(); List <DirectValueHolderRef> toPrefetch = new List <DirectValueHolderRef>(); List <IBackgroundWorkerDelegate> runnables = new List <IBackgroundWorkerDelegate>(); IEntityFactory entityFactory = this.EntityFactory; IdentityHashMap <IObjRef, StateEntry> newObjRefToStateEntryMap = new IdentityHashMap <IObjRef, StateEntry>(); IdentityHashMap <IChangeContainer, IChangeContainer> alreadyClonedMap = new IdentityHashMap <IChangeContainer, IChangeContainer>(); List <IChangeContainer> newAllChanges = new List <IChangeContainer>(allChanges.Count); for (int a = 0, size = allChanges.Count; a < size; a++) { IChangeContainer changeContainer = allChanges[a]; Object originalEntity = originalRefs[a]; StateEntry stateEntry = incrementalState.entityToStateMap.Get(originalEntity); IChangeContainer newChangeContainer; if (changeContainer is CreateContainer) { newChangeContainer = new CreateContainer(); } else if (changeContainer is UpdateContainer) { newChangeContainer = new UpdateContainer(); } else { newChangeContainer = new DeleteContainer(); } newAllChanges.Add(newChangeContainer); alreadyClonedMap.Put(changeContainer, newChangeContainer); if (!(changeContainer is CreateContainer)) { Object stateCacheEntity2 = allObjects[a]; stateEntry = incrementalState.entityToStateMap.Get(stateCacheEntity2); if (stateEntry == null) { stateEntry = new StateEntry(stateCacheEntity2, changeContainer.Reference, incrementalState.entityToStateMap.Count + 1); incrementalState.entityToStateMap.Put(stateCacheEntity2, stateEntry); incrementalState.objRefToStateMap.Put(stateEntry.objRef, stateEntry); } // delete & update do not need further handling continue; } Type realType = changeContainer.Reference.RealType; Object stateCacheEntity; if (stateEntry == null) { stateCacheEntity = entityFactory.CreateEntity(realType); DirectObjRef directObjRef = new DirectObjRef(realType, stateCacheEntity); directObjRef.CreateContainerIndex = a; stateEntry = new StateEntry(stateCacheEntity, directObjRef, incrementalState.entityToStateMap.Count + 1); incrementalState.entityToStateMap.Put(stateCacheEntity, stateEntry); incrementalState.objRefToStateMap.Put(stateEntry.objRef, stateEntry); newObjRefToStateEntryMap.Put(changeContainer.Reference, stateEntry); } else { stateCacheEntity = stateEntry.entity; } allObjects[a] = stateCacheEntity; } cloneStateTL.Value = new CloneState(newObjRefToStateEntryMap, incrementalState); try { for (int a = allChanges.Count; a-- > 0;) { IChangeContainer changeContainer = allChanges[a]; IObjRefContainer entity = (IObjRefContainer)allObjects[a]; changeContainer = FillClonedChangeContainer(changeContainer, alreadyClonedMap); IPrimitiveUpdateItem[] puis; IRelationUpdateItem[] ruis; if (changeContainer is CreateContainer) { CreateContainer createContainer = (CreateContainer)changeContainer; puis = createContainer.Primitives; ruis = createContainer.Relations; } else if (changeContainer is UpdateContainer) { UpdateContainer updateContainer = (UpdateContainer)changeContainer; puis = updateContainer.Primitives; ruis = updateContainer.Relations; } else { ((IDataObject)entity).ToBeDeleted = true; continue; } IEntityMetaData metaData = ((IEntityMetaDataHolder)entity).Get__EntityMetaData(); ApplyPrimitiveUpdateItems(entity, puis, metaData); if (ruis != null) { bool isUpdate = changeContainer is UpdateContainer; foreach (IRelationUpdateItem rui in ruis) { ApplyRelationUpdateItem(entity, rui, isUpdate, metaData, toPrefetch, toFetchFromCache, checkBaseState, runnables); } } } while (toPrefetch.Count > 0 || toFetchFromCache.Count > 0 || runnables.Count > 0) { if (toPrefetch.Count > 0) { PrefetchHelper.Prefetch(toPrefetch); toPrefetch.Clear(); } if (toFetchFromCache.Count > 0) { IList <Object> fetchedObjects = stateCache.GetObjects(toFetchFromCache, CacheDirective.None); hardRefs.Add(fetchedObjects); // add list as item intended. adding each item of the source is NOT needed toFetchFromCache.Clear(); } IBackgroundWorkerDelegate[] runnableArray = runnables.ToArray(); runnables.Clear(); foreach (IBackgroundWorkerDelegate runnable in runnableArray) { runnable(); } } List <Object> newObjects = new List <Object>(allObjects.Count); List <DirectValueHolderRef> changedRelationRefs = new List <DirectValueHolderRef>(); for (int a = allObjects.Count; a-- > 0;) { IChangeContainer newChange = newAllChanges[a]; IRelationUpdateItem[] ruis = null; Object entity = allObjects[a]; if (newChange is CreateContainer) { newObjects.Add(entity); ruis = ((CreateContainer)newChange).Relations; } else if (newChange is UpdateContainer) { ruis = ((UpdateContainer)newChange).Relations; } if (ruis == null) { continue; } IEntityMetaData metaData = EntityMetaDataProvider.GetMetaData(entity.GetType()); foreach (IRelationUpdateItem rui in ruis) { Member member = metaData.GetMemberByName(rui.MemberName); changedRelationRefs.Add(new DirectValueHolderRef((IObjRefContainer)entity, (RelationMember)member)); } } if (newObjects.Count > 0) { ((IWritableCache)stateCache).Put(newObjects); } if (changedRelationRefs.Count > 0) { PrefetchHelper.Prefetch(changedRelationRefs); } return(new CUDResult(newAllChanges, allObjects)); } finally { cloneStateTL.Value = null; } }
protected bool EqualsCUDResult(CUDResultDiff cudResultDiff) { ICUDResult left = cudResultDiff.left; ICUDResult right = cudResultDiff.right; IList <Object> leftRefs = left.GetOriginalRefs(); IList <Object> rightRefs = right.GetOriginalRefs(); if (leftRefs.Count != rightRefs.Count) { if (!cudResultDiff.doFullDiff) { return(false); } } IList <IChangeContainer> leftChanges = left.AllChanges; IList <IChangeContainer> rightChanges = right.AllChanges; IdentityHashMap <Object, int?> rightMap = IdentityHashMap <Object, int?> .Create(rightRefs.Count); for (int a = rightRefs.Count; a-- > 0;) { rightMap.Put(rightRefs[a], a); } for (int a = leftRefs.Count; a-- > 0;) { Object leftEntity = leftRefs[a]; int? rightIndex = rightMap.Remove(leftEntity); if (!rightIndex.HasValue) { if (!cudResultDiff.doFullDiff) { return(false); } cudResultDiff.diffChanges.Add(leftChanges[a]); cudResultDiff.originalRefs.Add(leftEntity); continue; } if (!EqualsChangeContainer(cudResultDiff, leftChanges[a], rightChanges[rightIndex.Value])) { if (!cudResultDiff.doFullDiff) { if (cudResultDiff.containerBuild != null) { throw new Exception(); } return(false); } cudResultDiff.diffChanges.Add(cudResultDiff.containerBuild); cudResultDiff.originalRefs.Add(rightRefs[rightIndex.Value]); cudResultDiff.containerBuild = null; } else if (cudResultDiff.containerBuild != null) { throw new Exception(); } } if (rightMap.Count == 0) { return(true); } foreach (Entry <Object, int> entry in rightMap) { Object rightRef = entry.Key; int rightIndex = entry.Value; IChangeContainer rightChange = rightChanges[rightIndex]; cudResultDiff.diffChanges.Add(rightChange); cudResultDiff.originalRefs.Add(rightRef); } return(false); }
protected bool EqualsChangeContainer(CUDResultDiff cudResultDiff, IChangeContainer left, IChangeContainer right) { if (left.GetType() != right.GetType()) { throw new Exception("Must never happen"); } cudResultDiff.SetLeftContainer(left); try { if (left is CreateContainer) { CreateContainer leftCreate = (CreateContainer)left; CreateContainer rightCreate = (CreateContainer)right; bool isEqual = EqualsPUIs(cudResultDiff, leftCreate.Primitives, rightCreate.Primitives); if (!isEqual) { if (!cudResultDiff.doFullDiff) { return(false); } } isEqual &= EqualsRUIs(cudResultDiff, leftCreate.Relations, rightCreate.Relations); if (!isEqual) { if (!cudResultDiff.doFullDiff) { return(false); } } return(isEqual); } if (left is UpdateContainer) { UpdateContainer leftUpdate = (UpdateContainer)left; UpdateContainer rightUpdate = (UpdateContainer)right; bool isEqual = EqualsPUIs(cudResultDiff, leftUpdate.Primitives, rightUpdate.Primitives); if (!isEqual) { if (!cudResultDiff.doFullDiff) { return(false); } } isEqual &= EqualsRUIs(cudResultDiff, leftUpdate.Relations, rightUpdate.Relations); if (!isEqual) { if (!cudResultDiff.doFullDiff) { return(false); } } return(isEqual); } // a DeleteContainer is only compared by the reference. But we know that this is already equal since we entered this method return(true); } finally { cudResultDiff.SetLeftContainer(null); } }
public IOriCollection Merge(ICUDResult cudResult, IMethodDescription methodDescription) { int localDcId; IDataChange dataChange; IList <IChangeContainer> allChanges = cudResult.AllChanges; IList <IObjRef> resultOriList = new List <IObjRef>(allChanges.Count); String changedBy = "anonymous"; long changedOn; Lock writeLock = PersistenceMock.GetWriteLock(); writeLock.Lock(); try { localDcId = ++dcId; changedOn = DateTimeUtil.CurrentTimeMillis(); IList <IDataChangeEntry> inserts = new List <IDataChangeEntry>(); IList <IDataChangeEntry> updates = new List <IDataChangeEntry>(); IList <IDataChangeEntry> deletes = new List <IDataChangeEntry>(); for (int a = 0, size = allChanges.Count; a < size; a++) { IChangeContainer changeContainer = allChanges[a]; IObjRef reference = changeContainer.Reference; if (changeContainer is DeleteContainer) { PersistenceMock.RemoveObject(reference); resultOriList.Add(null); deletes.Add(new DataChangeEntry(reference.RealType, reference.IdNameIndex, reference.Id, reference.Version)); } else if (changeContainer is UpdateContainer) { resultOriList.Add(reference); reference.Version = ((int)reference.Version) + 1; PersistenceMock.ChangeObject(reference, ((UpdateContainer)changeContainer).Primitives, ((UpdateContainer)changeContainer).Relations, changedBy, changedOn); updates.Add(new DataChangeEntry(reference.RealType, reference.IdNameIndex, reference.Id, reference.Version)); } else if (changeContainer is CreateContainer) { Object newId = AcquireIdForEntityType(reference.RealType); if (newId == null) { throw new Exception("Id must be valid"); } IEntityMetaData metaData = EntityMetaDataProvider.GetMetaData(reference.RealType); newId = ConversionHelper.ConvertValueToType(metaData.IdMember.ElementType, newId); reference.Id = newId; reference.Version = 1; ((IDirectObjRef)reference).Direct = null; resultOriList.Add(reference); PersistenceMock.AddObject(reference, ((CreateContainer)changeContainer).Primitives, ((CreateContainer)changeContainer).Relations, changedBy, changedOn); inserts.Add(new DataChangeEntry(reference.RealType, ObjRef.PRIMARY_KEY_INDEX, reference.Id, reference.Version)); } } OriCollection oriColl = new OriCollection(resultOriList); oriColl.ChangedBy = changedBy; oriColl.ChangedOn = changedOn; MergeController.ApplyChangesToOriginals(cudResult, oriColl, null); dataChange = new DataChangeEvent(inserts, updates, deletes, DateTimeUtil.ConvertJavaMillisToDateTime(changedOn), false); } finally { writeLock.Unlock(); } EventDispatcher.DispatchEvent(dataChange, dataChange.ChangeTime, localDcId); OriCollection oriCollection = new OriCollection(resultOriList); oriCollection.ChangedBy = changedBy; oriCollection.ChangedOn = changedOn; return(oriCollection); }
protected virtual void ProcessCUDResult(Object objectToMerge, ICUDResult cudResult, IList <Object> unpersistedObjectsToDelete, ProceedWithMergeHook proceedHook, bool addNewEntitiesToCache) { if (cudResult.AllChanges.Count > 0 || (unpersistedObjectsToDelete != null && unpersistedObjectsToDelete.Count > 0)) { if (proceedHook != null) { bool proceed = proceedHook.Invoke(cudResult, unpersistedObjectsToDelete); if (!proceed) { return; } } } if (cudResult.AllChanges.Count == 0) { if (Log.InfoEnabled) { Log.Info("Service call skipped early because there is nothing to merge"); } } else { IOriCollection oriColl; EventDispatcher.EnableEventQueue(); try { EventDispatcher.Pause(Cache); try { bool?oldNewlyPersistedEntities = addNewlyPersistedEntitiesTL.Value; addNewlyPersistedEntitiesTL.Value = addNewEntitiesToCache; try { IResultingBackgroundWorkerDelegate <IOriCollection> runnable = new IResultingBackgroundWorkerDelegate <IOriCollection>(delegate() { IOriCollection oriColl2 = MergeService.Merge(cudResult, null); MergeController.ApplyChangesToOriginals(cudResult, oriColl2, null); return(oriColl2); }); if (Transaction == null || Transaction.Active) { oriColl = runnable(); } else { oriColl = Transaction.RunInLazyTransaction(runnable); } } finally { addNewlyPersistedEntitiesTL.Value = oldNewlyPersistedEntities; } } finally { EventDispatcher.Resume(Cache); } } finally { EventDispatcher.FlushEventQueue(); } DataChangeEvent dataChange = DataChangeEvent.Create(-1, -1, -1); // This is intentionally a remote source dataChange.IsLocalSource = false; if (IsNetworkClientMode) { IList <IChangeContainer> allChanges = cudResult.AllChanges; IList <IObjRef> orisInReturn = oriColl.AllChangeORIs; for (int a = allChanges.Count; a-- > 0;) { IChangeContainer changeContainer = allChanges[a]; IObjRef reference = changeContainer.Reference; IObjRef referenceInReturn = orisInReturn[a]; if (changeContainer is CreateContainer) { if (referenceInReturn.IdNameIndex != ObjRef.PRIMARY_KEY_INDEX) { throw new ArgumentException("Implementation error: Only PK references are allowed in events"); } dataChange.Inserts.Add(new DataChangeEntry(referenceInReturn.RealType, referenceInReturn.IdNameIndex, referenceInReturn.Id, referenceInReturn.Version)); } else if (changeContainer is UpdateContainer) { if (referenceInReturn.IdNameIndex != ObjRef.PRIMARY_KEY_INDEX) { throw new ArgumentException("Implementation error: Only PK references are allowed in events"); } dataChange.Updates.Add(new DataChangeEntry(referenceInReturn.RealType, referenceInReturn.IdNameIndex, referenceInReturn.Id, referenceInReturn.Version)); } else if (changeContainer is DeleteContainer) { if (reference.IdNameIndex != ObjRef.PRIMARY_KEY_INDEX) { throw new ArgumentException("Implementation error: Only PK references are allowed in events"); } dataChange.Deletes.Add(new DataChangeEntry(reference.RealType, reference.IdNameIndex, reference.Id, reference.Version)); } } //EventDispatcher.DispatchEvent(dataChange, DateTime.Now, -1); } } if (unpersistedObjectsToDelete != null && unpersistedObjectsToDelete.Count > 0) { // Create a DCE for all objects without an id but which should be deleted... // This is the case for newly created objects on client side, which should be // "cancelled". The DCE notifies all models which contain identity references to the related // objects to erase their existence in all controls. They are not relevant in the previous // server merge process DataChangeEvent dataChange = DataChangeEvent.Create(0, 0, unpersistedObjectsToDelete.Count); for (int a = unpersistedObjectsToDelete.Count; a-- > 0;) { Object unpersistedObject = unpersistedObjectsToDelete[a]; dataChange.Deletes.Add(new DirectDataChangeEntry(unpersistedObject)); } EventDispatcher.DispatchEvent(dataChange, DateTime.Now, -1); } RevertChangesHelper.RevertChanges(objectToMerge); }
protected virtual void RemoveUnpersistedDeletedObjectsFromCudResult(IList <IChangeContainer> allChanges, IList <Object> originalRefs, IList <Object> unpersistedObjectsToDelete) { ISet <IObjRef> removedDirectObjRefs = null; for (int a = allChanges.Count; a-- > 0;) { IChangeContainer changeContainer = allChanges[a]; IObjRef objRef = changeContainer.Reference; if (!(changeContainer is DeleteContainer) || objRef.Id != null) { continue; } if (removedDirectObjRefs == null) { removedDirectObjRefs = new IdentityHashSet <IObjRef>(); } IDirectObjRef dirObjRef = (IDirectObjRef)objRef; // These are objects without an id but are marked as deleted. They will be deleted locally without transfer to the service allChanges.RemoveAt(a); originalRefs.RemoveAt(a); unpersistedObjectsToDelete.Add(dirObjRef.Direct); removedDirectObjRefs.Add(dirObjRef); } if (removedDirectObjRefs == null) { return; } // Scan all other changeContainer if they refer to the removed DeleteContainers of unpersisted entities for (int a = allChanges.Count; a-- > 0;) { IChangeContainer changeContainer = allChanges[a]; IRelationUpdateItem[] relations; if (changeContainer is CreateContainer) { relations = ((CreateContainer)changeContainer).Relations; } else if (changeContainer is UpdateContainer) { relations = ((UpdateContainer)changeContainer).Relations; } else { // DeleteContainers can not refer anything beside themselves continue; } if (relations == null) { continue; } for (int b = relations.Length; b-- > 0;) { IRelationUpdateItem childItem = relations[b]; IObjRef[] addedOris = childItem.AddedORIs; if (addedOris == null) { continue; } for (int c = addedOris.Length; c-- > 0;) { IObjRef addedOri = addedOris[c]; if (!removedDirectObjRefs.Contains(addedOri)) { continue; } if (addedOris.Length == 1) { if (childItem.RemovedORIs != null) { ((RelationUpdateItem)childItem).AddedORIs = null; } else { if (relations.Length == 1) { allChanges.RemoveAt(a); originalRefs.RemoveAt(a); relations = null; break; } IRelationUpdateItem[] newChildItems = new IRelationUpdateItem[relations.Length - 1]; Array.Copy(relations, 0, newChildItems, 0, b); Array.Copy(relations, b + 1, newChildItems, b, relations.Length - b - 1); relations = newChildItems; if (changeContainer is CreateContainer) { ((CreateContainer)changeContainer).Relations = relations; } else { ((UpdateContainer)changeContainer).Relations = relations; } } break; } IObjRef[] newAddedOris = new IObjRef[addedOris.Length - 1]; Array.Copy(addedOris, 0, newAddedOris, 0, c); Array.Copy(addedOris, c + 1, newAddedOris, c, addedOris.Length - c - 1); addedOris = newAddedOris; ((RelationUpdateItem)childItem).AddedORIs = addedOris; } if (relations == null) { break; } } } }