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 Dictionary <string, EntitiesProcessResult> SelectToManyFromViews(LoadRelatedPreProcessInfo preProcessInfo)
        {
            var viewSelectResult = new Dictionary <string, EntitiesProcessResult>();

            foreach (KeyValuePair <string, string[]> viewSelectionInfo in preProcessInfo.ViewsToSelect)
            {
                CouchViewOptions viewOptions = new CouchViewOptions
                {
                    IncludeDocs = true,
                    Keys        = viewSelectionInfo.Value.Cast <object>().ToList()
                };

                JToken[] rows = clientAdapter.GetViewRows(viewSelectionInfo.Key, viewOptions);
                EntitiesProcessResult processResult = Process(rows, new OdmViewProcessingOptions());

                viewSelectResult.Add(viewSelectionInfo.Key, processResult);
            }

            return(viewSelectResult);
        }