private void LoadRelatedPostProcess <T>(
            IEnumerable <T> sourceEntities,
            LoadRelatedOptions options, LoadRelatedPreProcessInfo preProcessInfo)
        {
            JToken[] rows = ClientAdaper.GetDocuments(preProcessInfo.EntityIdsToLoad);
            EntitiesProcessResult processResult = Process(rows, new OdmViewProcessingOptions());

            Dictionary <string, EntitiesProcessResult> viewsSelectResult = SelectToManyFromViews(preProcessInfo);

            foreach (T sourceEntity in sourceEntities)
            {
                string entityId = GetEntityInstanceId(sourceEntity);
                JToken document = DocumentManager.DocInfo(entityId).Document;

                // ToOne
                foreach (PropertyInfo toOneProp in options.ToOne)
                {
                    string relatedEntityId    = GetRelatedToOneEntityId(document, toOneProp);
                    object relatedToOneEntity = processResult.GetEntity(relatedEntityId);

                    // This line was comment out because it is possible to get null related entity
                    // when the property is optional. This check needs to be done only for required properties.
                    //if (relatedToOneEntity == null) throw new Exception("Fail to find ToOne related entity for property " + toOneProp);
                    toOneProp.SetValue(sourceEntity, relatedToOneEntity);
                }

                // ToOne already loaded
                foreach (PropertyInfo toOneProp in options.ToOneExist)
                {
                    string relatedEntityId    = GetRelatedToOneEntityId(document, toOneProp);
                    object relatedToOneEntity = identityMap.GetEntityById(relatedEntityId);
                    if (relatedToOneEntity == null)
                    {
                        throw new Exception("Fail to find ToOneExist related entity for property " + toOneProp);
                    }
                    toOneProp.SetValue(sourceEntity, relatedToOneEntity);
                }

                // ToMany Direct
                foreach (PropertyInfo toManyDirectProp in options.ToManyDirect)
                {
                    string[] relatedEntitiesIds = GetRelatedToManyEntitiesIds(document, toManyDirectProp);
                    if (relatedEntitiesIds != null)
                    {
                        serializer.SetDirectAssoicationCollectionProperty(sourceEntity, toManyDirectProp, relatedEntitiesIds);
                    }
                }

                // ToMany Inverse
                foreach (LoadRelatedWithViewInfo toManyViewInfo in options.ToManyView)
                {
                    EntitiesProcessResult viewProcessResult = viewsSelectResult[toManyViewInfo.ViewName];
                    string[] relatedEntitiesIds             = viewProcessResult.GetRelatedEntitiesIds(entityId);

                    AssociationAttribute associationAttr = AssociationAttribute.GetSingle(toManyViewInfo.PropertyInfo);
                    serializer.SetInverseAssociationCollectionInternal(
                        sourceEntity, toManyViewInfo.PropertyInfo, associationAttr, relatedEntitiesIds);
                }
            }
        }
        /// <summary>
        /// Load specified related entities of the sourceEntities.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sourceEntities"></param>
        /// <param name="configOptions"></param>
        public void LoadRelated <T>(IEnumerable <T> sourceEntities, Action <LoadRelatedOptionsBuilder <T> > configOptions)
        {
            var optionsBuilder = new LoadRelatedOptionsBuilder <T>();

            configOptions(optionsBuilder);
            LoadRelatedOptions options = optionsBuilder.Build();

            // First pre-process all the source entities and find the relatd entities to load.
            LoadRelatedPreProcessInfo preProcessInfo = LoadRelatedPreProcess(sourceEntities, options);

            // Load the related entities and set the association properties.
            LoadRelatedPostProcess(sourceEntities, options, preProcessInfo);
        }
        private LoadRelatedPreProcessInfo LoadRelatedPreProcess <T>(IEnumerable <T> sourceEntities, LoadRelatedOptions options)
        {
            var builder = new LoadRelatedPreProcessInfoBuilder();

            foreach (T sourceEntity in sourceEntities)
            {
                string entityId = GetEntityInstanceId(sourceEntity);
                JToken document = DocumentManager.DocInfo(entityId).Document;

                Debug.Assert(document != null, "Fail to find the original document of the entity " + sourceEntity);

                // Find all ToOne associations to load
                foreach (PropertyInfo toOneProp in options.ToOne)
                {
                    string relatedEntityId = GetRelatedToOneEntityId(document, toOneProp);
                    if (!string.IsNullOrEmpty(relatedEntityId))
                    {
                        builder.RelatedEntityIdsToLoad.Add(relatedEntityId);
                    }
                }

                // Find all ToMany associations to load
                foreach (PropertyInfo toManyDirectProp in options.ToManyDirect)
                {
                    string[] relatedEntitiesIds = GetRelatedToManyEntitiesIds(document, toManyDirectProp) ?? new string[0];
                    foreach (string relatedEntityId in relatedEntitiesIds)
                    {
                        builder.RelatedEntityIdsToLoad.Add(relatedEntityId);
                    }
                }

                // Prepare all Inverse-ToMany with views.
                foreach (LoadRelatedWithViewInfo inverseToMany in options.ToManyView)
                {
                    builder.AddViewSelection(inverseToMany.ViewName, GetEntityInstanceId(sourceEntity));
                }
            }

            return(builder.Build());
        }