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 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 bool HandleValueHolder(DirectValueHolderRef vhr, PrefetchPath[] cachePaths, 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) { RelationMember member = vhr.Member; bool newOriToLoad = false; if (vhr is IndirectValueHolderRef) { RootCacheValue rcv = (RootCacheValue)vhr.Vhc; ICacheIntern rootCache = ((IndirectValueHolderRef)vhr).RootCache; IEntityMetaData metaData = EntityMetaDataProvider.GetMetaData(rcv.EntityType); int relationIndex = metaData.GetIndexByRelation(member); IObjRef[] rcvObjRefs = rcv.GetRelation(relationIndex); if (rcvObjRefs == null) { IObjRelation self = ValueHolderContainerMixin.GetSelf(rcv, member.Name); ISet <IObjRelation> orelsLoadedHistory = cacheToOrelsLoadedHistory.Get(rootCache); if (orelsLoadedHistory == null || !orelsLoadedHistory.Contains(self)) { IMap <IObjRelation, bool> orelsToLoad = cacheToOrelsToLoad.Get(rootCache); if (orelsToLoad == null) { orelsToLoad = new HashMap <IObjRelation, bool>(); cacheToOrelsToLoad.Put(rootCache, orelsToLoad); } orelsToLoad.Put(self, vhr.ObjRefsOnly); AddCascadeLoadItem(vhr, cachePaths, cascadeLoadItems); } return(false); } else if (!vhr.ObjRefsOnly && rcvObjRefs.Length > 0) { ISet <IObjRef> orisLoadedHistory = cacheToOrisLoadedHistory.Get(rootCache); for (int b = rcvObjRefs.Length; b-- > 0;) { IObjRef ori = rcvObjRefs[b]; if (orisLoadedHistory != null && orisLoadedHistory.Contains(ori)) { // Object has been tried to load before but it is obviously not in the cache // So the load must have been failed somehow. It is assumed that the entity // is not persisted in the database anymore (deleted before) so the ORI is illegal. // We cleanup the ValueHolder so that future calls will not lead to // another unnecessary roundtrip to the server rcvObjRefs[b] = null; continue; } IISet <IObjRef> orisToLoad = cacheToOrisToLoad.Get(rootCache); if (orisToLoad == null) { orisToLoad = new CHashSet <IObjRef>(); cacheToOrisToLoad.Put(rootCache, orisToLoad); } orisToLoad.Add(ori); newOriToLoad = true; } if (newOriToLoad) { AddCascadeLoadItem(vhr, cachePaths, cascadeLoadItems); } } return(false); } IValueHolderContainer vhc = (IValueHolderContainer)vhr.Vhc; int relationIndex2 = vhc.Get__EntityMetaData().GetIndexByRelationName(member.Name); if (ValueHolderState.INIT == vhc.Get__State(relationIndex2)) { return(true); } ICacheIntern cache = vhc.__TargetCache; IObjRef[] objRefs = vhc.Get__ObjRefs(relationIndex2); if (objRefs == null) { IObjRelation self = vhc.Get__Self(relationIndex2); List <IObjRelation> orels = new List <IObjRelation>(); orels.Add(self); IList <IObjRelationResult> orelResults = cache.GetObjRelations(orels, cache, failEarlyReturnMisses); IObjRelationResult orelResult = orelResults[0]; if (orelResult == null) { ISet <IObjRelation> orelsLoadedHistory = cacheToOrelsLoadedHistory.Get(cache); if (orelsLoadedHistory == null || !orelsLoadedHistory.Contains(self)) { IMap <IObjRelation, bool> orelsToLoad = cacheToOrelsToLoad.Get(cache); if (orelsToLoad == null) { orelsToLoad = new HashMap <IObjRelation, bool>(); cacheToOrelsToLoad.Put(cache, orelsToLoad); } orelsToLoad.Put(self, vhr.ObjRefsOnly); AddCascadeLoadItem(vhr, cachePaths, cascadeLoadItems); } return(false); } objRefs = orelResult.Relations; if (objRefs != null) { vhc.Set__ObjRefs(relationIndex2, objRefs); } } if (!vhr.ObjRefsOnly && objRefs != null && objRefs.Length > 0) { IList <Object> loadedObjects = cache.GetObjects(new List <IObjRef>(objRefs), cache, failEarlyReturnMisses); try { for (int b = objRefs.Length; b-- > 0;) { IObjRef ori = objRefs[b]; Object loadedObject = loadedObjects[b]; if (loadedObject != null) { continue; } ISet <IObjRef> orisLoadedHistory = cacheToOrisLoadedHistory.Get(cache); if (orisLoadedHistory != null && orisLoadedHistory.Contains(ori)) { // Object has been tried to load before but it is obviously not in the cache // So the load must have been failed somehow. It is assumed that the entity // is not persisted in the database anymore (deleted before) so the ORI is illegal. // We cleanup the ValueHolder so that future calls will not lead to // another unnecessary roundtrip to the server objRefs[b] = null; continue; } IISet <IObjRef> orisToLoad = cacheToOrisToLoad.Get(cache); if (orisToLoad == null) { orisToLoad = new CHashSet <IObjRef>(); cacheToOrisToLoad.Put(cache, orisToLoad); } orisToLoad.Add(ori); newOriToLoad = true; } } finally { loadedObjects.Clear(); loadedObjects = null; } } if (objRefs == null || newOriToLoad) { AddCascadeLoadItem(vhr, cachePaths, cascadeLoadItems); return(false); } return(true); }
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); } } }