protected void ScanForInitializedObjects(Object obj, ISet <Object> alreadyScannedObjects, ISet <IObjRef> objRefs) { if (obj == null || !alreadyScannedObjects.Add(obj)) { return; } if (obj is IList) { IList list = (IList)obj; for (int a = list.Count; a-- > 0;) { Object item = list[a]; ScanForInitializedObjects(item, alreadyScannedObjects, objRefs); } return; } if (obj is IEnumerable) { foreach (Object item in (IEnumerable)obj) { ScanForInitializedObjects(item, alreadyScannedObjects, objRefs); } return; } IEntityMetaData metaData = ((IEntityMetaDataHolder)obj).Get__EntityMetaData(); Object id = metaData.IdMember.GetValue(obj, false); if (id == null) { // This may happen if a normally retrieved object gets deleted and therefore has lost its primary id // TODO: The object is still contained in the cache, maybe this should be reviewed return; } ObjRef objRef = new ObjRef(metaData.EntityType, ObjRef.PRIMARY_KEY_INDEX, id, null); objRefs.Add(objRef); RelationMember[] relationMembers = metaData.RelationMembers; if (relationMembers.Length == 0) { return; } IObjRefContainer vhc = (IObjRefContainer)obj; for (int relationIndex = relationMembers.Length; relationIndex-- > 0;) { RelationMember relationMember = relationMembers[relationIndex]; if (ValueHolderState.INIT != vhc.Get__State(relationIndex)) { continue; } Object value = relationMember.GetValue(obj, false); ScanForInitializedObjects(value, alreadyScannedObjects, objRefs); } }
protected virtual void Persist(Object obj, MergeHandle handle) { IEntityMetaData metaData = ((IEntityMetaDataHolder)obj).Get__EntityMetaData(); AddModification(obj, handle); // Ensure entity will be persisted even if no single property is specified RelationMember[] relationMembers = metaData.RelationMembers; if (relationMembers.Length > 0) { IObjRefContainer vhc = (IObjRefContainer)obj; for (int relationIndex = relationMembers.Length; relationIndex-- > 0;) { RelationMember relationMember = relationMembers[relationIndex]; if (ValueHolderState.INIT != vhc.Get__State(relationIndex)) { continue; } Object objMember = relationMember.GetValue(obj, false); if (objMember == null) { continue; } AddOriModification(obj, relationMember.Name, objMember, null, handle); } } foreach (PrimitiveMember primitiveMember in metaData.PrimitiveMembers) { if (primitiveMember.TechnicalMember) { continue; } Object objMember = primitiveMember.GetValue(obj, true); if (objMember != null) { AddModification(obj, primitiveMember.Name, primitiveMember.ElementType, objMember, null, handle); } } }
protected void FindAllObjectsToBackup(Object obj, IList <Object> objList, IList <IObjRef> objRefs, ISet <Object> alreadyProcessedSet) { if (obj == null || !alreadyProcessedSet.Add(obj)) { return; } // In java there has to be checked (in addition) for array-instance, too if (obj is IList) { IList list = (IList)obj; for (int a = list.Count; a-- > 0;) { Object item = list[a]; FindAllObjectsToBackup(item, objList, objRefs, alreadyProcessedSet); } return; } else if (obj is IEnumerable) { IEnumerator iter = ((IEnumerable)obj).GetEnumerator(); while (iter.MoveNext()) { Object item = iter.Current; FindAllObjectsToBackup(item, objList, objRefs, alreadyProcessedSet); } return; } IEntityMetaData metaData = ((IEntityMetaDataHolder)obj).Get__EntityMetaData(); Object id = metaData.IdMember.GetValue(obj); objList.Add(obj); objRefs.Add(new ObjRef(metaData.EntityType, ObjRef.PRIMARY_KEY_INDEX, id, null)); RelationMember[] relationMembers = metaData.RelationMembers; for (int a = relationMembers.Length; a-- > 0;) { RelationMember relationMember = relationMembers[a]; Object item = relationMember.GetValue(obj); FindAllObjectsToBackup(item, objList, objRefs, alreadyProcessedSet); } }
public IObjRef[][] ExtractRelations(IEntityMetaData metaData, Object obj, IList <Object> relationValues) { RelationMember[] relationMembers = metaData.RelationMembers; if (relationMembers.Length == 0) { return(ObjRef.EMPTY_ARRAY_ARRAY); } IValueHolderContainer vhc = (IValueHolderContainer)obj; IObjRef[][] relations = new IObjRef[relationMembers.Length][]; IObjRefHelper objRefHelper = this.ObjRefHelper; for (int relationIndex = relationMembers.Length; relationIndex-- > 0;) { RelationMember relationMember = relationMembers[relationIndex]; if (ValueHolderState.INIT != vhc.Get__State(relationIndex)) { relations[relationIndex] = vhc.Get__ObjRefs(relationIndex); continue; } Object relationValue = relationMember.GetValue(obj, false); if (relationValue == null) { relations[relationIndex] = ObjRef.EMPTY_ARRAY; continue; } IList <IObjRef> oris = objRefHelper.ExtractObjRefList(relationValue, null); relations[relationIndex] = oris != null?ListUtil.ToArray <IObjRef>(oris) : null; if (relationValues != null) { relationValues.Add(relationValue); } } return(relations); }
protected virtual void Merge(Object obj, Object clone, MergeHandle handle) { IEntityMetaDataProvider entityMetaDataProvider = this.EntityMetaDataProvider; IEntityMetaData metaData = ((IEntityMetaDataHolder)obj).Get__EntityMetaData(); bool fieldBasedMergeActive = handle.FieldBasedMergeActive; bool oneChangeOccured = false; try { RelationMember[] relationMembers = metaData.RelationMembers; if (relationMembers.Length > 0) { IObjRefContainer vhc = (IObjRefContainer)obj; for (int relationIndex = relationMembers.Length; relationIndex-- > 0;) { RelationMember relationMember = relationMembers[relationIndex]; if (!metaData.IsMergeRelevant(relationMember)) { continue; } if (ValueHolderState.INIT != vhc.Get__State(relationIndex)) { // v2 valueholder is not initialized. so a change is impossible continue; } Object objMember = relationMember.GetValue(obj, false); Object cloneMember = relationMember.GetValue(clone, false); if (objMember is IDataObject && !((IDataObject)objMember).HasPendingChanges) { IEntityMetaData relationMetaData = entityMetaDataProvider.GetMetaData(relationMember.RealType); if (EqualsReferenceOrId(objMember, cloneMember, handle, relationMetaData)) { continue; } } IEntityMetaData childMetaData = entityMetaDataProvider.GetMetaData(relationMember.ElementType); if (IsMemberModified(objMember, cloneMember, handle, childMetaData)) { oneChangeOccured = true; AddOriModification(obj, relationMember.Name, objMember, cloneMember, handle); } } } if (fieldBasedMergeActive) { MergePrimitivesFieldBased(metaData, obj, clone, handle); return; } bool additionalRound; do { additionalRound = !oneChangeOccured; foreach (PrimitiveMember primitiveMember in metaData.PrimitiveMembers) { if (!metaData.IsMergeRelevant(primitiveMember)) { continue; } Object objValue = primitiveMember.GetValue(obj, true); if (oneChangeOccured) { AddModification(obj, primitiveMember.Name, primitiveMember.ElementType, objValue, null, handle); continue; } Object cloneValue = primitiveMember.GetValue(clone, true); if (!ArePrimitivesEqual(metaData, primitiveMember, objValue, cloneValue, handle)) { oneChangeOccured = true; break; } } }while (additionalRound && oneChangeOccured); } finally { PrimitiveMember versionMember = metaData.VersionMember; if (oneChangeOccured && versionMember != null) { // Check for early optimistic locking (Another, later level is directly on persistence layer) Object versionToMerge = versionMember.GetValue(obj, true); Object currentVersion = versionMember.GetValue(clone, true); int compareResult = ((IComparable)versionToMerge).CompareTo(currentVersion); if (ExactVersionForOptimisticLockingRequired ? compareResult != 0 : compareResult < 0) { throw new OptimisticLockException(currentVersion, versionToMerge, obj); } } } }
protected void ScanForInitializedObjectsIntern(Object obj, bool isDeepMerge, IList <Object> objects, IMap <Type, IList <Object> > typeToObjectsToMerge, ISet <Object> alreadyHandledObjectsSet, IList <IObjRef> objRefs, IList <ValueHolderRef> valueHolderKeys) { if (obj == null || !alreadyHandledObjectsSet.Add(obj)) { return; } if (obj is IList) { IList list = (IList)obj; for (int a = 0, size = list.Count; a < size; a++) { ScanForInitializedObjectsIntern(list[a], isDeepMerge, objects, typeToObjectsToMerge, alreadyHandledObjectsSet, objRefs, valueHolderKeys); } return; } else if (obj.GetType().IsArray) { Array array = (Array)obj; for (int a = array.Length; a-- > 0;) { Object item = array.GetValue(a); ScanForInitializedObjectsIntern(item, isDeepMerge, objects, typeToObjectsToMerge, alreadyHandledObjectsSet, objRefs, valueHolderKeys); } return; } else if (obj is IEnumerable && !(obj is String)) { foreach (Object item in (IEnumerable)obj) { ScanForInitializedObjectsIntern(item, isDeepMerge, objects, typeToObjectsToMerge, alreadyHandledObjectsSet, objRefs, valueHolderKeys); } return; } IEntityMetaData metaData = EntityMetaDataProvider.GetMetaData(obj.GetType(), true); if (metaData == null) { return; } IObjRef objRef = null; Object id = metaData.IdMember.GetValue(obj, false); if (id != null) { objRef = ObjRefFactory.CreateObjRef(metaData.EntityType, ObjRef.PRIMARY_KEY_INDEX, id, null); objRef.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic); } if (!(obj is IDataObject) || ((IDataObject)obj).HasPendingChanges) { if (typeToObjectsToMerge != null) { IList <Object> objectsToMerge = typeToObjectsToMerge.Get(metaData.EntityType); if (objectsToMerge == null) { objectsToMerge = new List <Object>(); typeToObjectsToMerge.Put(metaData.EntityType, objectsToMerge); } objectsToMerge.Add(obj); } objects.Add(obj); objRefs.Add(objRef); } if (!isDeepMerge) { return; } RelationMember[] relationMembers = metaData.RelationMembers; if (relationMembers.Length == 0) { return; } IObjRefContainer vhc = (IObjRefContainer)obj; for (int relationIndex = relationMembers.Length; relationIndex-- > 0;) { if (ValueHolderState.INIT != vhc.Get__State(relationIndex)) { continue; } RelationMember relationMember = relationMembers[relationIndex]; Object item = relationMember.GetValue(obj); if (objRef != null && item != null) { ValueHolderRef vhk = new ValueHolderRef(objRef, relationMember, relationIndex); valueHolderKeys.Add(vhk); } ScanForInitializedObjectsIntern(item, isDeepMerge, objects, typeToObjectsToMerge, alreadyHandledObjectsSet, objRefs, valueHolderKeys); } }
protected void ApplyRelationUpdateItem(IObjRefContainer entity, IRelationUpdateItem rui, bool isUpdate, IEntityMetaData metaData, IList <DirectValueHolderRef> toPrefetch, List <IObjRef> toFetchFromCache, bool checkBaseState, IList <IBackgroundWorkerDelegate> runnables) { IObjRefHelper objRefHelper = this.ObjRefHelper; String memberName = rui.MemberName; int relationIndex = metaData.GetIndexByRelationName(memberName); RelationMember relationMember = metaData.RelationMembers[relationIndex]; IObjRef[] existingORIs; if (entity.Is__Initialized(relationIndex)) { existingORIs = ListUtil.ToArray(ObjRefHelper.ExtractObjRefList(relationMember.GetValue(entity), null)); } else { existingORIs = entity.Get__ObjRefs(relationIndex); if (existingORIs == null) { toPrefetch.Add(new DirectValueHolderRef(entity, relationMember, true)); runnables.Add(new IBackgroundWorkerDelegate(delegate() { ApplyRelationUpdateItem(entity, rui, isUpdate, metaData, toPrefetch, toFetchFromCache, checkBaseState, runnables); })); return; } } IObjRef[] addedORIs = rui.AddedORIs; IObjRef[] removedORIs = rui.RemovedORIs; IObjRef[] newORIs; if (existingORIs.Length == 0) { if (checkBaseState && removedORIs != null) { throw new Exception("Removing from empty member"); } newORIs = addedORIs != null ? (IObjRef[])addedORIs.Clone() : ObjRef.EMPTY_ARRAY; for (int a = newORIs.Length; a-- > 0;) { newORIs[a] = CloneObjRef(newORIs[a], false); } } else { // Set to efficiently remove entries LinkedHashSet <IObjRef> existingORIsSet = new LinkedHashSet <IObjRef>(existingORIs); if (removedORIs != null) { foreach (IObjRef removedORI in removedORIs) { IObjRef clonedObjRef = CloneObjRef(removedORI, false); if (existingORIsSet.Remove(clonedObjRef) || !checkBaseState) { continue; } throw OptimisticLockUtil.ThrowModified(objRefHelper.EntityToObjRef(entity), null, entity); } } if (addedORIs != null) { foreach (IObjRef addedORI in addedORIs) { IObjRef clonedObjRef = CloneObjRef(addedORI, false); if (existingORIsSet.Add(clonedObjRef) || !checkBaseState) { continue; } throw OptimisticLockUtil.ThrowModified(objRefHelper.EntityToObjRef(entity), null, entity); } } if (existingORIsSet.Count == 0) { newORIs = ObjRef.EMPTY_ARRAY; } else { newORIs = existingORIsSet.ToArray(); } } if (!entity.Is__Initialized(relationIndex)) { entity.Set__ObjRefs(relationIndex, newORIs); return; } toFetchFromCache.AddRange(newORIs); runnables.Add(new IBackgroundWorkerDelegate(delegate() { ICache stateCache = cloneStateTL.Value.incrementalState.GetStateCache(); IList <Object> objects = stateCache.GetObjects(newORIs, CacheDirective.FailEarly); Object value; if (relationMember.IsToMany) { // To-many relation Object coll = ListUtil.CreateObservableCollectionOfType(relationMember.RealType, objects.Count); ListUtil.FillList(coll, objects); value = coll; } else { // To-one relation value = objects.Count > 0 ? objects[0] : null; } relationMember.SetValue(entity, value); })); }
protected void EnsureInitializedRelationsIntern3(Object obj, PrefetchPath[] cachePaths, ILinkedMap <Type, PrefetchPath[]> entityTypeToPrefetchPaths, IMap <ICacheIntern, IISet <IObjRef> > cacheToOrisToLoad, IMap <ICacheIntern, IMap <IObjRelation, bool> > cacheToOrelsToLoad, IMap <ICacheIntern, IISet <IObjRef> > cacheToOrisLoadedHistory, IMap <ICacheIntern, IISet <IObjRelation> > cacheToOrelsLoadedHistory, AlreadyHandledSet alreadyHandledSet, IList <PrefetchCommand> cascadeLoadItems) { if (obj == null) { return; } if (!alreadyHandledSet.PutIfNotExists(obj, cachePaths, true)) { return; } if (obj is IndirectValueHolderRef) { IndirectValueHolderRef vhk = (IndirectValueHolderRef)obj; HandleValueHolder(vhk, cachePaths, cacheToOrisToLoad, cacheToOrelsToLoad, cacheToOrisLoadedHistory, cacheToOrelsLoadedHistory, alreadyHandledSet, cascadeLoadItems); // Do nothing because this is only to prefetch RootCache entries return; } else if (obj is DirectValueHolderRef) { DirectValueHolderRef vhk = (DirectValueHolderRef)obj; if (!HandleValueHolder(vhk, cachePaths, cacheToOrisToLoad, cacheToOrelsToLoad, cacheToOrisLoadedHistory, cacheToOrelsLoadedHistory, alreadyHandledSet, cascadeLoadItems)) { return; } // force valueholder init. at this point we know that all related items are already in the cache. there will be no roundtrip // to the server if (vhk.Member == null) { obj = vhk.Vhc; } else { obj = vhk.Member.GetValue(vhk.Vhc); } } if (obj == null) { // this check is necessary because even if we create only instances of DirectValueHolderRef in cases where there is a not initalized relation // even then it might be possible that a concurrent thread initializes the valueholder to null (e.g. an empty to-one relation) return; } if ((cachePaths == null || cachePaths.Length == 0) && entityTypeToPrefetchPaths == null) { return; } if (obj is IEnumerable) { var items = new List <Object>(); foreach (Object item in (IEnumerable)obj) { if (item == null) { continue; } items.Add(item); } foreach (Object item in items) { EnsureInitializedRelationsIntern3(item, cachePaths, entityTypeToPrefetchPaths, cacheToOrisToLoad, cacheToOrelsToLoad, cacheToOrisLoadedHistory, cacheToOrelsLoadedHistory, alreadyHandledSet, cascadeLoadItems); } return; } IEntityMetaData metaData = ((IEntityMetaDataHolder)obj).Get__EntityMetaData(); if (cachePaths == null || cachePaths.Length == 0) { if (entityTypeToPrefetchPaths != null) { cachePaths = entityTypeToPrefetchPaths.Get(metaData.EntityType); } if (cachePaths == null || cachePaths.Length == 0) { return; } } RelationMember[] relationMembers = metaData.RelationMembers; if (relationMembers.Length == 0) { return; } IValueHolderContainer vhc = (IValueHolderContainer)obj; for (int a = cachePaths.Length; a-- > 0;) { PrefetchPath path = cachePaths[a]; int relationIndex = path.memberIndex; RelationMember member = relationMembers[relationIndex]; if (ValueHolderState.INIT != vhc.Get__State(relationIndex)) { DirectValueHolderRef vhk = new DirectValueHolderRef(vhc, member); EnsureInitializedRelationsIntern3(vhk, path.children, entityTypeToPrefetchPaths, cacheToOrisToLoad, cacheToOrelsToLoad, cacheToOrisLoadedHistory, cacheToOrelsLoadedHistory, alreadyHandledSet, cascadeLoadItems); continue; } Object memberValue = member.GetValue(obj); if (memberValue == null) { continue; } EnsureInitializedRelationsIntern3(memberValue, path.children, entityTypeToPrefetchPaths, cacheToOrisToLoad, cacheToOrelsToLoad, cacheToOrisLoadedHistory, cacheToOrelsLoadedHistory, alreadyHandledSet, cascadeLoadItems); } }
protected void HandleValueHolderContainer(IValueHolderContainer vhc, RelationMember[] relationMembers, IObjRef[][] relations) { ICacheHelper cacheHelper = this.CacheHelper; ICacheIntern parent = this.Parent; IProxyHelper proxyHelper = this.ProxyHelper; for (int relationIndex = relationMembers.Length; relationIndex-- > 0;) { RelationMember relationMember = relationMembers[relationIndex]; IObjRef[] relationsOfMember = relations[relationIndex]; if (!CascadeLoadMode.EAGER.Equals(relationMember.CascadeLoadMode)) { if (ValueHolderState.INIT != vhc.Get__State(relationIndex)) { // Update ObjRef information within the entity and do nothing else vhc.Set__ObjRefs(relationIndex, relationsOfMember); continue; } } // We can safely access to relation if we want to if (relationsOfMember == null) { // Reset value holder state because we do not know the content currently vhc.Set__Uninitialized(relationIndex, null); continue; } Object relationValue = relationMember.GetValue(vhc); if (relationsOfMember.Length == 0) { if (!relationMember.IsToMany) { if (relationValue != null) { // Relation has to be flushed relationMember.SetValue(vhc, null); } } else { if (relationValue != null) { // Reuse existing collection ListUtil.ClearList(relationValue); } else { // We have to create a new empty collection relationValue = cacheHelper.CreateInstanceOfTargetExpectedType(relationMember.RealType, relationMember.ElementType); relationMember.SetValue(vhc, relationValue); } } continue; } // So we know the new content (which is not empty) and we know that the current content is already initialized // Now we have to refresh the current content eagerly // load entities as if we were an "eager valueholder" here IList <Object> potentialNewItems = parent.GetObjects(new List <IObjRef>(relationsOfMember), this, CacheDirective.None); if (OverwriteToManyRelations) { Object newRelationValue = cacheHelper.ConvertResultListToExpectedType(potentialNewItems, relationMember.RealType, relationMember.ElementType); // Set new to-many-relation, even if there has not changed anything in its item content relationMember.SetValue(vhc, newRelationValue); continue; } IList <Object> relationItems = ListUtil.AnyToList(relationValue); bool diff = (relationItems.Count != potentialNewItems.Count); if (!diff) { for (int b = potentialNewItems.Count; b-- > 0;) { if (!Object.ReferenceEquals(potentialNewItems[b], relationItems[b])) { diff = true; break; } } } if (!diff) { // Nothing to do continue; } if (relationValue != null && relationMember.IsToMany) { // Reuse existing collection ListUtil.ClearAndFillList(relationValue, relationItems); } else { // We have to create a new empty collection or replace the to-one value Object newRelationValue = cacheHelper.ConvertResultListToExpectedType(potentialNewItems, relationMember.RealType, relationMember.ElementType); relationMember.SetValue(vhc, newRelationValue); } } }