/// <summary>
 /// Read object from data record
 /// </summary>
 /// <param name="record">Data record</param>
 /// <param name="path">Current property path</param>
 /// <returns>Object</returns>
 internal abstract object TakeObject(DataRecord record, string path);
        /// <summary>
        /// Execute query and return data map
        /// </summary>
        private IEnumerable <T> ExecuteQuery <T>(IDbCommand command, string[] outputParameters, DataAliasCollection settings, EntityMappingCollection mappings, EntityMapperCollection mappers, DataReflectorCollection reflectors, object bag)
        {
            // Get root path
            var rootPath = outputParameters[0];

            using (var reader = command.ExecuteReader())
            {
                var record = new DataRecord(reader, mappers, reflectors, bag);

                int index = 0;
                do
                {
                    try
                    {
                        // Set path
                        record.SetPath(outputParameters[index]);

                        // Substitute stored procedure field names to manual mapped field names
                        for (int i = 0; i < reader.FieldCount; i++)
                        {
                            record.AddField(settings.Get(outputParameters[index], reader.GetName(i)), i);
                        }

                        // Detect current iteration type
                        if (index == 0)
                        {
                            // Detect primary reader for map
                            EntityMapper <T> entityMapper = mappers.Get <T>();
                            if (entityMapper == null)
                            {
                                throw new DataLayerException(Properties.Resources.PrimaryMapperNotRegistered);
                            }

                            // Register types of current path in cache
                            record.InitCache(typeof(T), typeof(List <T>), outputParameters[index]);

                            // Read data from stream
                            //if (reader.HasRows)
                            while (reader.Read())
                            {
                                entityMapper.ReadEntity(record, outputParameters[index]);
                            }
                        }
                        else
                        {
                            // Take relative and ending path
                            var relativePath = GetRelativePath(outputParameters[index]);
                            var endingPath   = GetEndingPath(outputParameters[index]);

                            // Determine target entity type path
                            var entityType = record.GetEntityType(relativePath);
                            if (entityType == null)
                            {
                                continue;
                            }

                            // Take mapping
                            var mapping = mappings.GetMapping(entityType, endingPath);
                            if (mapping == null)
                            {
                                throw new DataLayerException(string.Format(Properties.Resources.MappingNotSpecified, endingPath));
                            }

                            // Detect reader registered for specified path
                            EntityMapper entityMapper = mappers.Get(mapping.ChildType);
                            if (entityMapper == null)
                            {
                                continue;
                            }

                            // Register types of current path in cache
                            record.InitCache(mapping.ChildType, mapping.ChildListType, outputParameters[index]);

                            // Read data from stream and reflect it to primary entitiy
                            //if (reader.HasRows)
                            while (reader.Read())
                            {
                                entityMapper.ReadEntity(record, outputParameters[index]);
                            }

                            // Taking left entities
                            var parentEntities = record.TakeEntities(relativePath);
                            if (parentEntities == null)
                            {
                                break;
                            }

                            // Taking child entities
                            var childEntities = record.TakeEntities(outputParameters[index]);

                            // Invoke join operation
                            foreach (var parent in parentEntities)
                            {
                                if (!mapping.IsMatch(parent))
                                {
                                    continue;
                                }
                                List <object> result = new List <object>();
                                if (childEntities != null)
                                {
                                    foreach (var child in childEntities)
                                    {
                                        if (mapping.JoinCondition(parent, child))
                                        {
                                            result.Add(child);
                                        }
                                    }
                                }

                                if (result != null)
                                {
                                    mapping.Setter(parent, result);
                                }
                            }
                        }
                    }
                    finally
                    {
                        index++;
                    }
                }while (reader.NextResult());

                return(record.TakeEntities <T>(rootPath));
            }
        }
 /// <summary>
 /// Read entity from data record
 /// </summary>
 /// <param name="record">Data record</param>
 /// <param name="path">Current property path</param>
 /// <returns>Entity</returns>
 internal abstract object ReadEntity(DataRecord record, string path);
 /// <summary>
 /// Get acceptance of readed entity
 /// </summary>
 /// <param name="record">Data record</param>
 /// <param name="path">Property path</param>
 /// <returns>Acceptance</returns>
 protected internal virtual bool CanRead(DataRecord record, string path)
 {
     return(true);
 }
 /// <summary>
 /// Read entity from data source
 /// </summary>
 /// <param name="record">Data source image</param>
 /// <param name="path">Current relative path</param>
 /// <returns>Entity</returns>
 protected abstract T Read(DataRecord record, string path);
 /// <summary>
 /// Fill specified entity from data source
 /// </summary>
 /// <param name="entity">Entity to fill</param>
 /// <param name="record">Data source image</param>
 /// <param name="path">Current relative path</param>
 protected virtual void Fill(T entity, DataRecord record, string path)
 {
 }
 internal override object TakeObject(DataRecord record, string path)
 {
     return(TakeEntity(record, path));
 }