public coreModel.Category[] GetByIds(string[] categoryIds, coreModel.CategoryResponseGroup responseGroup, string catalogId = null)
        {
            coreModel.Category[] result;

            using (var repository = _catalogRepositoryFactory())
            {
                result = repository.GetCategoriesByIds(categoryIds, responseGroup)
                    .Select(c => c.ToCoreModel())
                    .ToArray();
            }

            // Fill outlines for products
            if (responseGroup.HasFlag(coreModel.CategoryResponseGroup.WithOutlines))
            {
                _outlineService.FillOutlinesForObjects(result, catalogId);
            }

            // Fill SEO info
            if ((responseGroup & coreModel.CategoryResponseGroup.WithSeo) == coreModel.CategoryResponseGroup.WithSeo)
            {
                var objectsWithSeo = new List<ISeoSupport>(result);

                var outlineItems = result
                    .Where(c => c.Outlines != null)
                    .SelectMany(c => c.Outlines.SelectMany(o => o.Items));
                objectsWithSeo.AddRange(outlineItems);

                _commerceService.LoadSeoForObjects(objectsWithSeo.ToArray());
            }

            return result;
        }
        public coreModel.CatalogProduct[] GetByIds(string[] itemIds, coreModel.ItemResponseGroup respGroup, string catalogId = null)
        {
            if (respGroup.HasFlag(coreModel.ItemResponseGroup.Outlines))
            {
                respGroup |= coreModel.ItemResponseGroup.Links;
            }

            coreModel.CatalogProduct[] result;

            using (var repository = _catalogRepositoryFactory())
            {
                result = repository.GetItemByIds(itemIds, respGroup)
                    .Select(x => x.ToCoreModel())
                    .ToArray();
            }

            // Fill outlines for products
            if (respGroup.HasFlag(coreModel.ItemResponseGroup.Outlines))
            {
                _outlineService.FillOutlinesForObjects(result, catalogId);
            }

            // Fill SEO info for products, variations and outline items
            if ((respGroup & coreModel.ItemResponseGroup.Seo) == coreModel.ItemResponseGroup.Seo)
            {
                var objectsWithSeo = new List<ISeoSupport>(result);

                var variations = result.Where(p => p.Variations != null)
                                       .SelectMany(p => p.Variations);
                objectsWithSeo.AddRange(variations);

                var outlineItems = result.Where(p => p.Outlines != null)
                                         .SelectMany(p => p.Outlines.SelectMany(o => o.Items));
                objectsWithSeo.AddRange(outlineItems);

                _commerceService.LoadSeoForObjects(objectsWithSeo.ToArray());
            }

            return result;
        }
        public dataModel.Item[] GetItemByIds(string[] itemIds, coreModel.ItemResponseGroup respGroup = coreModel.ItemResponseGroup.ItemLarge)
        {
            if (itemIds == null)
            {
                throw new ArgumentNullException("itemIds");
            }

            if (!itemIds.Any())
            {
                return new dataModel.Item[] { };
            }

            // Use breaking query EF performance concept https://msdn.microsoft.com/en-us/data/hh949853.aspx#8
            var retVal = Items.Include(x => x.Images).Where(x => itemIds.Contains(x.Id)).ToArray();
            var propertyValues = PropertyValues.Where(x => itemIds.Contains(x.ItemId)).ToArray();

            // Load product catalogs separately
            var catalogIds = retVal.Select(x => x.CatalogId).Distinct().ToArray();
            var catalogs = Catalogs.Include(x => x.CatalogLanguages).Where(x => catalogIds.Contains(x.Id)).ToArray();

            // Load product categories separately
            var categoryIds = retVal.Select(x => x.CategoryId).Where(x => !string.IsNullOrEmpty(x)).Distinct().ToArray();
            var categoriesReponseGroup = coreModel.CategoryResponseGroup.WithParents;

            if (respGroup.HasFlag(coreModel.ItemResponseGroup.Outlines))
            {
                categoriesReponseGroup |= coreModel.CategoryResponseGroup.WithLinks;
            }

            if (respGroup.HasFlag(coreModel.ItemResponseGroup.ItemProperties))
            {
                // Load categories with all properties for property inheritance
                categoriesReponseGroup |= coreModel.CategoryResponseGroup.WithProperties;
            }

            var categories = GetCategoriesByIds(categoryIds, categoriesReponseGroup);

            if (respGroup.HasFlag(coreModel.ItemResponseGroup.Links) || respGroup.HasFlag(coreModel.ItemResponseGroup.Outlines))
            {
                var relations = CategoryItemRelations.Where(x => itemIds.Contains(x.ItemId)).ToArray();
            }

            // Load all properties meta information and data for inheritance from parent categories and catalog
            if (respGroup.HasFlag(coreModel.ItemResponseGroup.ItemProperties))
            {
                // Load catalogs with properties for products not belongs to any category (EF auto populated all Catalog nav properties for all objects)
                foreach (var catalogId in retVal.Where(x => x.CategoryId == null).Select(x => x.CatalogId))
                {
                    var catalog = GetCatalogById(catalogId);
                }
            }

            if (respGroup.HasFlag(coreModel.ItemResponseGroup.ItemAssets))
            {
                var assets = Assets.Where(x => itemIds.Contains(x.ItemId)).ToArray();
            }

            if (respGroup.HasFlag(coreModel.ItemResponseGroup.ItemEditorialReviews))
            {
                var editorialReviews = EditorialReviews.Where(x => itemIds.Contains(x.ItemId)).ToArray();
            }

            if (respGroup.HasFlag(coreModel.ItemResponseGroup.Variations))
            {
                var variationIds = Items.Where(x => itemIds.Contains(x.ParentId)).Select(x => x.Id).ToArray();
                // For variations load only info and images
                var variations = Items.Include(x => x.Images).Include(x => x.Assets).Where(x => variationIds.Contains(x.Id)).ToArray();
                // Load variations property values separately
                var variationPropertyValues = PropertyValues.Where(x => variationIds.Contains(x.ItemId)).ToArray();
            }

            if (respGroup.HasFlag(coreModel.ItemResponseGroup.ItemAssociations))
            {
                var assosiationGroups = AssociationGroups.Include(x => x.Associations).ToArray();
                var assosiatedItemIds = assosiationGroups.SelectMany(x => x.Associations).Select(x => x.ItemId).Distinct().ToArray();
                var assosiationItems = GetItemByIds(assosiatedItemIds, coreModel.ItemResponseGroup.ItemInfo);
            }

            // Load parents
            var parentIds = retVal.Where(x => x.Parent == null && x.ParentId != null).Select(x => x.ParentId).ToArray();
            var parents = GetItemByIds(parentIds, respGroup);
            return retVal;
        }
        public dataModel.Category[] GetCategoriesByIds(string[] categoriesIds, coreModel.CategoryResponseGroup respGroup)
        {
            if (categoriesIds == null)
            {
                throw new ArgumentNullException("categoriesIds");
            }

            if (!categoriesIds.Any())
            {
                return new dataModel.Category[] { };
            }

            var result = Categories.Include(x => x.Catalog.CatalogLanguages)
                                   .Where(x => categoriesIds.Contains(x.Id)).ToArray();

            if (respGroup.HasFlag(coreModel.CategoryResponseGroup.WithLinks))
            {
                var incommingLinks = CategoryLinks.Where(x => categoriesIds.Contains(x.TargetCategoryId)).ToArray();
                var outgoingLinks = CategoryLinks.Where(x => categoriesIds.Contains(x.SourceCategoryId)).ToArray();
            }

            if (respGroup.HasFlag(coreModel.CategoryResponseGroup.WithImages))
            {
                var images = Images.Where(x => categoriesIds.Contains(x.CategoryId)).ToArray();
            }

            if (respGroup.HasFlag(coreModel.CategoryResponseGroup.WithParents) || respGroup.HasFlag(coreModel.CategoryResponseGroup.WithProperties))
            {
                var parentsMap = GetAllCategoriesParents(categoriesIds);
                foreach (var categoryId in categoriesIds)
                {
                    var category = result.FirstOrDefault(x => x.Id == categoryId);
                    if (category != null)
                    {
                        category.AllParents = parentsMap[categoryId];
                    }
                }
            }

            //Load category property values by separate query
            var propertyValues = PropertyValues.Where(x => categoriesIds.Contains(x.CategoryId)).ToArray();

            //Load all properties meta information and information for inheritance
            if (respGroup.HasFlag(coreModel.CategoryResponseGroup.WithProperties))
            {
                //Need load inherited from parents categories and catalogs
                var allParents = result.SelectMany(x => x.AllParents).ToArray();
                var allCategoriesTreeIds = allParents.Select(x => x.Id).Concat(categoriesIds).Distinct().ToArray();
                var allCatalogsIds = result.Select(x => x.CatalogId).Concat(allParents.Select(x => x.CatalogId)).Distinct().ToArray();

                var categoriesProperties = Properties.Include(x => x.PropertyAttributes)
                                           .Include(x => x.DictionaryValues)
                                           .Where(x => allCategoriesTreeIds.Contains(x.CategoryId)).ToArray();

                var catalogProperties = Properties.Include(x => x.PropertyAttributes)
                                           .Include(x => x.DictionaryValues)
                                           .Where(x => x.CategoryId == null && allCatalogsIds.Contains(x.CatalogId)).ToArray();
            }

            return result;
        }