private void SearchCategories(SearchCriteria criteria, SearchResult result) { // TODO: optimize for performance, need to eliminate number of database queries // 1. Catalog should either be passed or loaded using caching // 2. Categories should be loaded by passing array of ids instead of parallel loading one by one using (var repository = _catalogRepositoryFactory()) { var query = repository.Categories.Where(x => criteria.WithHidden ? true : x.IsActive); //Get list of search in categories var searchCategoryIds = criteria.CategoryIds; if (searchCategoryIds != null && searchCategoryIds.Any() && criteria.SearchInChildren) { searchCategoryIds = searchCategoryIds.Concat(repository.GetAllChildrenCategoriesIds(searchCategoryIds)).ToArray(); } //Filter by keyword in all categories if (!string.IsNullOrEmpty(criteria.Keyword)) { query = query.Where(x => x.Name.Contains(criteria.Keyword) || x.Code.Contains(criteria.Keyword)); } else if (searchCategoryIds != null && searchCategoryIds.Any()) { if (criteria.HideDirectLinkedCategories) { query = query.Where(x => searchCategoryIds.Contains(x.ParentCategoryId) || x.OutgoingLinks.Any(y => searchCategoryIds.Contains(y.TargetCategory.ParentCategoryId))); } else { query = query.Where(x => searchCategoryIds.Contains(x.ParentCategoryId) || x.OutgoingLinks.Any(y => searchCategoryIds.Contains(y.TargetCategoryId))); } } else if (!string.IsNullOrEmpty(criteria.Code)) { query = query.Where(x => x.Code == criteria.Code); } else if (criteria.CatalogIds != null) { query = query.Where(x => (criteria.CatalogIds.Contains(x.CatalogId) && (x.ParentCategoryId == null || criteria.SearchInChildren)) || (x.OutgoingLinks.Any(y => y.TargetCategoryId == null && criteria.CatalogIds.Contains(y.TargetCatalogId)))); } var categoryIds = query.Select(x => x.Id).ToArray(); var categoryResponseGroup = CategoryResponseGroup.Info | CategoryResponseGroup.WithImages | CategoryResponseGroup.WithSeo | CategoryResponseGroup.WithLinks | CategoryResponseGroup.WithParents; if ((criteria.ResponseGroup & SearchResponseGroup.WithProperties) == SearchResponseGroup.WithProperties) { categoryResponseGroup |= CategoryResponseGroup.WithProperties; } result.Categories = _categoryService.GetByIds(categoryIds, categoryResponseGroup) .OrderByDescending(x => x.Priority) .ThenBy(x => x.Name) .ToList(); } }
public moduleModel.SearchResult SearchItems(CatalogIndexedSearchCriteria criteria, moduleModel.ItemResponseGroup responseGroup) { CatalogItemSearchResults results; var items = Search(criteria, out results, responseGroup); var response = new moduleModel.SearchResult(); response.Products.AddRange(items); response.ProductsTotalCount = results.TotalCount; // TODO need better way to find applied filter values var appliedFilters = criteria.CurrentFilters.SelectMany(x => x.GetValues()).Select(x => x.Id).ToArray(); if (results.FacetGroups != null) { response.Aggregations = results.FacetGroups.Select(g => g.ToModuleModel(appliedFilters)).ToArray(); } return response; }
private void SearchCatalogs(coreModel.SearchCriteria criteria, coreModel.SearchResult result) { using (var repository = _catalogRepositoryFactory()) { var catalogIds = repository.Catalogs.Select(x => x.Id).ToArray(); var catalogs = new ConcurrentBag <coreModel.Catalog>(); var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = 10 }; Parallel.ForEach(catalogIds, parallelOptions, (x) => { var catalog = _catalogService.GetById(x); catalogs.Add(catalog); }); result.Catalogs = catalogs.OrderByDescending(x => x.Name).ToList(); } }
public moduleModel.SearchResult SearchItems(CatalogIndexedSearchCriteria criteria, moduleModel.ItemResponseGroup responseGroup) { CatalogItemSearchResults results; var items = Search(criteria, out results, responseGroup); var response = new moduleModel.SearchResult(); response.Products.AddRange(items); response.ProductsTotalCount = results.TotalCount; // TODO need better way to find applied filter values var appliedFilters = criteria.CurrentFilters.SelectMany(x => x.GetValues()).Select(x => x.Id).ToArray(); if (results.FacetGroups != null) { response.Aggregations = results.FacetGroups.Select(g => g.ToModuleModel(appliedFilters)).ToArray(); } return(response); }
public coreModel.SearchResult Search(coreModel.SearchCriteria criteria) { var retVal = new coreModel.SearchResult(); var taskList = new List<Task>(); if ((criteria.ResponseGroup & coreModel.ResponseGroup.WithProducts) == coreModel.ResponseGroup.WithProducts) { taskList.Add(Task.Factory.StartNew(() => SearchItems(criteria, retVal))); } if ((criteria.ResponseGroup & coreModel.ResponseGroup.WithCatalogs) == coreModel.ResponseGroup.WithCatalogs) { taskList.Add(Task.Factory.StartNew(() => SearchCatalogs(criteria, retVal))); } if ((criteria.ResponseGroup & coreModel.ResponseGroup.WithCategories) == coreModel.ResponseGroup.WithCategories) { taskList.Add(Task.Factory.StartNew(() => SearchCategories(criteria, retVal))); } Task.WaitAll(taskList.ToArray()); return retVal; }
public coreModel.SearchResult Search(coreModel.SearchCriteria criteria) { var retVal = new coreModel.SearchResult(); var taskList = new List <Task>(); if ((criteria.ResponseGroup & coreModel.ResponseGroup.WithProducts) == coreModel.ResponseGroup.WithProducts) { taskList.Add(Task.Factory.StartNew(() => SearchItems(criteria, retVal))); } if ((criteria.ResponseGroup & coreModel.ResponseGroup.WithCatalogs) == coreModel.ResponseGroup.WithCatalogs) { taskList.Add(Task.Factory.StartNew(() => SearchCatalogs(criteria, retVal))); } if ((criteria.ResponseGroup & coreModel.ResponseGroup.WithCategories) == coreModel.ResponseGroup.WithCategories) { taskList.Add(Task.Factory.StartNew(() => SearchCategories(criteria, retVal))); } Task.WaitAll(taskList.ToArray()); return(retVal); }
public static webModel.CatalogSearchResult ToWebModel(this coreModel.SearchResult result, IBlobUrlResolver blobUrlResolver) { var retVal = new webModel.CatalogSearchResult(); retVal.InjectFrom(result); if (result.Products != null) { retVal.Products = result.Products.Select(x => x.ToWebModel(blobUrlResolver)).ToArray(); } if (result.Categories != null) { retVal.Categories = result.Categories.Select(x => x.ToWebModel(blobUrlResolver)).ToArray(); } if (result.Aggregations != null) { retVal.Aggregations = result.Aggregations.Select(a => a.ToWebModel()).ToArray(); } return(retVal); }
public static webModel.CatalogSearchResult ToWebModel(this coreModel.SearchResult result, IBlobUrlResolver blobUrlResolver) { var retVal = new webModel.CatalogSearchResult(); retVal.ProductsTotalCount = result.ProductsTotalCount; if (result.Products != null) { //Parallel conversation for better performance var preservedOrder = result.Products.Select(x => x.Id).ToList(); var productDtos = new ConcurrentBag <CatalogModule.Web.Model.Product>(); Parallel.ForEach(result.Products, (x) => { productDtos.Add(x.ToWebModel(blobUrlResolver)); }); retVal.Products = productDtos.OrderBy(i => preservedOrder.IndexOf(i.Id)).ToArray(); } if (result.Categories != null) { var preservedOrder = result.Categories.Select(x => x.Id).ToList(); var categoryDtos = new ConcurrentBag <CatalogModule.Web.Model.Category>(); Parallel.ForEach(result.Categories, (x) => { categoryDtos.Add(x.ToWebModel(blobUrlResolver)); }); retVal.Categories = categoryDtos.OrderBy(i => preservedOrder.IndexOf(i.Id)).ToArray(); } if (result.Aggregations != null) { retVal.Aggregations = result.Aggregations.Select(a => a.ToWebModel()).ToArray(); } return(retVal); }
private void SearchCategories(coreModel.SearchCriteria criteria, coreModel.SearchResult result) { // TODO: optimize for performance, need to eliminate number of database queries // 1. Catalog should either be passed or loaded using caching // 2. Categories should be loaded by passing array of ids instead of parallel loading one by one using (var repository = _catalogRepositoryFactory()) { var query = repository.Categories; dataModel.CatalogBase dbCatalog = null; var isVirtual = false; if (!String.IsNullOrEmpty(criteria.CatalogId)) { dbCatalog = repository.GetCatalogById(criteria.CatalogId); isVirtual = dbCatalog is dataModel.VirtualCatalog; query = query.Where(x => x.CatalogId == criteria.CatalogId); } if (!String.IsNullOrEmpty(criteria.Keyword)) { query = query.Where(x => x.Name.Contains(criteria.Keyword) || x.Code.Contains(criteria.Keyword)); } else if (!String.IsNullOrEmpty(criteria.CategoryId)) { if (isVirtual) { var dbCategory = repository.GetCategoryById(criteria.CategoryId); //Need return all linked categories also var allLinkedPhysicalCategoriesIds = dbCategory.IncommingLinks.Select(x => x.SourceCategoryId).ToArray(); query = repository.Categories; if (allLinkedPhysicalCategoriesIds.Any()) { if (criteria.HideDirectLinedCategories) { query = query.Where(x => x.ParentCategoryId == criteria.CategoryId || allLinkedPhysicalCategoriesIds.Contains(x.ParentCategoryId)); } else { query = query.Where(x => x.ParentCategoryId == criteria.CategoryId || allLinkedPhysicalCategoriesIds.Contains(x.Id)); } } else { query = query.Where(x => x.ParentCategoryId == criteria.CategoryId); } } else { query = query.Where(x => x.ParentCategoryId == criteria.CategoryId); } } else if (!String.IsNullOrEmpty(criteria.Code)) { query = query.Where(x => x.Code == criteria.Code); } else if (!String.IsNullOrEmpty(criteria.SeoKeyword)) { var urlKeyword = _commerceService.GetSeoByKeyword(criteria.SeoKeyword).Where(x => x.ObjectType == typeof(coreModel.Category).Name).FirstOrDefault(); if (urlKeyword == null) { query = query.Where(x => false); } else { query = query.Where(x => x.Id == urlKeyword.ObjectId); } } else if (!String.IsNullOrEmpty(criteria.CatalogId)) { query = query.Where(x => x.CatalogId == criteria.CatalogId && (x.ParentCategoryId == null || criteria.GetAllCategories)); if (isVirtual) { //Need return only catalog linked categories var allLinkedCategoriesIds = ((dataModel.VirtualCatalog)dbCatalog).IncommingLinks .Where(x => x.TargetCategoryId == null) .Select(x => x.SourceCategoryId); //Search in all catalogs query = repository.Categories; query = query.Where(x => (x.CatalogId == criteria.CatalogId && (x.ParentCategoryId == null || criteria.GetAllCategories)) || allLinkedCategoriesIds.Contains(x.Id)); } } var categoryIds = query.Select(x => x.Id).ToArray(); var categories = new ConcurrentBag <coreModel.Category>(); var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = 10 }; Parallel.ForEach(categoryIds, parallelOptions, (x) => { var category = _categoryService.GetById(x); categories.Add(category); }); //Must order by priority result.Categories = categories.OrderByDescending(x => x.Priority).ThenBy(x => x.Name).ToList(); } }
private void SearchItems(coreModel.SearchCriteria criteria, coreModel.SearchResult result) { using (var repository = _catalogRepositoryFactory()) { var searchInAllCategories = criteria.GetAllCategories || !String.IsNullOrEmpty(criteria.Keyword); var isVirtual = false; if (criteria.CatalogId != null) { var dbCatalog = repository.GetCatalogById(criteria.CatalogId); isVirtual = dbCatalog is dataModel.VirtualCatalog; } var query = repository.Items; if ((criteria.ResponseGroup & coreModel.ResponseGroup.WithVariations) != coreModel.ResponseGroup.WithVariations) { query = query.Where(x => x.ParentId == null); } if (!searchInAllCategories && !String.IsNullOrEmpty(criteria.CategoryId)) { if (isVirtual) { var dbCategory = repository.GetCategoryById(criteria.CategoryId); ////Need return all items belongs to linked categories //var allLinkedPhysicalCategoriesIds = dbCategory.IncommingLinks.Select(x => x.SourceCategoryId).ToArray(); query = query.Where(x => x.CategoryId == criteria.CategoryId || x.CategoryLinks.Any(c => c.CategoryId == criteria.CategoryId)); } else { query = query.Where(x => x.CategoryId == criteria.CategoryId); } } else if (!String.IsNullOrEmpty(criteria.CatalogId)) { query = query.Where(x => x.CatalogId == criteria.CatalogId && (searchInAllCategories || x.CategoryId == null)); } if (!String.IsNullOrEmpty(criteria.Code)) { query = query.Where(x => x.Code == criteria.Code); } else if (!String.IsNullOrEmpty(criteria.SeoKeyword)) { var urlKeyword = _commerceService.GetSeoByKeyword(criteria.SeoKeyword).Where(x => x.ObjectType == typeof(coreModel.CatalogProduct).Name).FirstOrDefault(); if (urlKeyword == null) { query = query.Where(x => false); } else { query = query.Where(x => x.Id == urlKeyword.ObjectId); } } else if (!String.IsNullOrEmpty(criteria.Keyword)) { query = query.Where(x => x.Name.Contains(criteria.Keyword) || x.Code.Contains(criteria.Keyword)); } result.TotalCount = query.Count(); var itemIds = query.OrderByDescending(x => x.Name) .Skip(criteria.Start) .Take(criteria.Count) .Select(x => x.Id) .ToArray(); var productResponseGroup = coreModel.ItemResponseGroup.ItemInfo | coreModel.ItemResponseGroup.ItemAssets | ItemResponseGroup.Categories; if ((criteria.ResponseGroup & coreModel.ResponseGroup.WithProperties) == coreModel.ResponseGroup.WithProperties) { productResponseGroup |= coreModel.ItemResponseGroup.ItemProperties; } if ((criteria.ResponseGroup & coreModel.ResponseGroup.WithVariations) == coreModel.ResponseGroup.WithVariations) { productResponseGroup |= coreModel.ItemResponseGroup.Variations; } var products = _itemService.GetByIds(itemIds, productResponseGroup); result.Products = products.OrderByDescending(x => x.Name).ToList(); } }
private void SearchCategories(SearchCriteria criteria, SearchResult result) { using (var repository = _catalogRepositoryFactory()) { var query = repository.Categories.Where(x => criteria.WithHidden || x.IsActive); //Get list of search in categories var searchCategoryIds = criteria.CategoryIds; if (!searchCategoryIds.IsNullOrEmpty()) { if (criteria.SearchInChildren) { searchCategoryIds = searchCategoryIds.Concat(repository.GetAllChildrenCategoriesIds(searchCategoryIds)).ToArray(); //linked categories var allLinkedCategories = repository.CategoryLinks.Where(x => searchCategoryIds.Contains(x.TargetCategoryId)).Select(x => x.SourceCategoryId).ToArray(); searchCategoryIds = searchCategoryIds.Concat(allLinkedCategories).Distinct().ToArray(); } if (criteria.HideDirectLinkedCategories) { query = query.Where(x => searchCategoryIds.Contains(x.ParentCategoryId) || x.OutgoingLinks.Any(y => searchCategoryIds.Contains(y.TargetCategory.ParentCategoryId))); } else { query = query.Where(x => searchCategoryIds.Contains(x.ParentCategoryId) || x.OutgoingLinks.Any(y => searchCategoryIds.Contains(y.TargetCategoryId))); } } else if (!criteria.CatalogIds.IsNullOrEmpty()) { if (criteria.SearchInChildren) { //need search in all catalog linked and children categories //First need load all categories belong to searched catalogs searchCategoryIds = repository.Categories.Where(x => criteria.CatalogIds.Contains(x.CatalogId)).Select(x => x.Id).ToArray(); //Then load all physical categories linked to catalog var allCatalogLinkedCategories = repository.CategoryLinks.Where(x => criteria.CatalogIds.Contains(x.TargetCatalogId)).Select(x => x.SourceCategoryId).ToArray(); searchCategoryIds = searchCategoryIds.Concat(allCatalogLinkedCategories).Distinct().ToArray(); //Then expand all categories, get all children's searchCategoryIds = searchCategoryIds.Concat(repository.GetAllChildrenCategoriesIds(searchCategoryIds)).ToArray(); if (!searchCategoryIds.IsNullOrEmpty()) { //find all categories belong searched catalogs and all categories direct or implicitly linked to catalogs query = query.Where(x => searchCategoryIds.Contains(x.Id)); } } else { query = query.Where(x => (criteria.CatalogIds.Contains(x.CatalogId) && x.ParentCategoryId == null) || (x.OutgoingLinks.Any(y => y.TargetCategoryId == null && criteria.CatalogIds.Contains(y.TargetCatalogId)))); } } if (!string.IsNullOrEmpty(criteria.Keyword)) { query = query.Where(x => x.Name.Contains(criteria.Keyword) || x.Code.Contains(criteria.Keyword)); } else if (!string.IsNullOrEmpty(criteria.Code)) { query = query.Where(x => x.Code == criteria.Code); } var sortInfos = criteria.SortInfos; if (sortInfos.IsNullOrEmpty()) { sortInfos = new[] { new SortInfo { SortColumn = "Name" } }; } //Try to replace sorting columns names TryTransformSortingInfoColumnNames(_categorySortingAliases, sortInfos); query = query.OrderBySortInfos(sortInfos); var categoryIds = query.Select(x => x.Id).ToArray(); var categoryResponseGroup = CategoryResponseGroup.Info | CategoryResponseGroup.WithImages | CategoryResponseGroup.WithSeo | CategoryResponseGroup.WithLinks | CategoryResponseGroup.WithParents; if ((criteria.ResponseGroup & SearchResponseGroup.WithProperties) == SearchResponseGroup.WithProperties) { categoryResponseGroup |= CategoryResponseGroup.WithProperties; } if ((criteria.ResponseGroup & SearchResponseGroup.WithOutlines) == SearchResponseGroup.WithOutlines) { categoryResponseGroup |= CategoryResponseGroup.WithOutlines; } result.Categories = _categoryService.GetByIds(categoryIds, categoryResponseGroup, criteria.CatalogId) .AsQueryable() .OrderBySortInfos(sortInfos) .ToList(); } }
private void SearchItems(SearchCriteria criteria, SearchResult result) { using (var repository = _catalogRepositoryFactory()) { //list of search categories var searchCategoryIds = criteria.CategoryIds; if (criteria.SearchInChildren) { if (!searchCategoryIds.IsNullOrEmpty()) { searchCategoryIds = searchCategoryIds.Concat(repository.GetAllChildrenCategoriesIds(searchCategoryIds)).ToArray(); //linked categories var allLinkedCategories = repository.CategoryLinks.Where(x => searchCategoryIds.Contains(x.TargetCategoryId)).Select(x => x.SourceCategoryId).ToArray(); searchCategoryIds = searchCategoryIds.Concat(allLinkedCategories).Distinct().ToArray(); } else if (!criteria.CatalogIds.IsNullOrEmpty()) { //If category not specified need search in all linked and children categories searchCategoryIds = repository.Categories.Where(x => criteria.CatalogIds.Contains(x.CatalogId)).Select(x => x.Id).ToArray(); var allCatalogLinkedCategories = repository.CategoryLinks.Where(x => criteria.CatalogIds.Contains(x.TargetCatalogId)).Select(x => x.SourceCategoryId).ToArray(); searchCategoryIds = searchCategoryIds.Concat(allCatalogLinkedCategories).Distinct().ToArray(); } } var query = repository.Items.Where(x => criteria.WithHidden || x.IsActive); if (!criteria.SearchInVariations) { query = query.Where(x => x.ParentId == null); } if (!searchCategoryIds.IsNullOrEmpty()) { query = query.Where(x => searchCategoryIds.Contains(x.CategoryId) || x.CategoryLinks.Any(c => searchCategoryIds.Contains(c.CategoryId))); } else if (!criteria.CatalogIds.IsNullOrEmpty()) { query = query.Where(x => criteria.CatalogIds.Contains(x.CatalogId) && (criteria.SearchInChildren || x.CategoryId == null)); } if (!string.IsNullOrEmpty(criteria.Code)) { query = query.Where(x => x.Code == criteria.Code); } else if (!string.IsNullOrEmpty(criteria.Keyword)) { query = query.Where(x => x.Name.Contains(criteria.Keyword) || x.Code.Contains(criteria.Keyword) || x.ItemPropertyValues.Any(y => y.ShortTextValue == criteria.Keyword)); } //Filter by property dictionary values if (!criteria.PropertyValues.IsNullOrEmpty()) { var propValueIds = criteria.PropertyValues.Select(x => x.ValueId).Distinct().ToArray(); query = query.Where(x => x.ItemPropertyValues.Any(y => propValueIds.Contains(y.KeyValue))); } if (!criteria.ProductTypes.IsNullOrEmpty()) { query = query.Where(x => criteria.ProductTypes.Contains(x.ProductType)); } if (criteria.OnlyBuyable != null) { query = query.Where(x => x.IsBuyable == criteria.OnlyBuyable); } if (criteria.OnlyWithTrackingInventory != null) { query = query.Where(x => x.TrackInventory == criteria.OnlyWithTrackingInventory); } result.ProductsTotalCount = query.Count(); var sortInfos = criteria.SortInfos; if (sortInfos.IsNullOrEmpty()) { sortInfos = new[] { new SortInfo { SortColumn = "Name" } }; } //Try to replace sorting columns names TryTransformSortingInfoColumnNames(_productSortingAliases, sortInfos); query = query.OrderBySortInfos(sortInfos); var itemIds = query.Skip(criteria.Skip) .Take(criteria.Take) .Select(x => x.Id) .ToArray(); var productResponseGroup = ItemResponseGroup.ItemInfo | ItemResponseGroup.ItemAssets | ItemResponseGroup.Links | ItemResponseGroup.Seo; if ((criteria.ResponseGroup & SearchResponseGroup.WithProperties) == SearchResponseGroup.WithProperties) { productResponseGroup |= ItemResponseGroup.ItemProperties; } if ((criteria.ResponseGroup & SearchResponseGroup.WithVariations) == SearchResponseGroup.WithVariations) { productResponseGroup |= ItemResponseGroup.Variations; } if ((criteria.ResponseGroup & SearchResponseGroup.WithOutlines) == SearchResponseGroup.WithOutlines) { productResponseGroup |= ItemResponseGroup.Outlines; } var products = _itemService.GetByIds(itemIds, productResponseGroup, criteria.CatalogId); result.Products = products.AsQueryable().OrderBySortInfos(sortInfos).ToList(); } }
private void SearchCatalogs(SearchCriteria criteria, SearchResult result) { using (var repository = _catalogRepositoryFactory()) { var catalogIds = criteria.CatalogIds; if (catalogIds.IsNullOrEmpty()) { catalogIds = repository.Catalogs.Select(x => x.Id).ToArray(); } var catalogs = new ConcurrentBag<Catalog>(); var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = 10 }; Parallel.ForEach(catalogIds, parallelOptions, catalogId => { var catalog = _catalogService.GetById(catalogId); catalogs.Add(catalog); }); result.Catalogs = catalogs.OrderByDescending(x => x.Name).ToList(); } }
private void SearchItems(SearchCriteria criteria, SearchResult result) { using (var repository = _catalogRepositoryFactory()) { //list of search categories var searchCategoryIds = criteria.CategoryIds; if (searchCategoryIds != null && criteria.SearchInChildren) { searchCategoryIds = searchCategoryIds.Concat(repository.GetAllChildrenCategoriesIds(searchCategoryIds)).ToArray(); //linked categories var allLinkedCategories = repository.CategoryLinks.Where(x => searchCategoryIds.Contains(x.TargetCategoryId)).Select(x => x.SourceCategoryId).ToArray(); searchCategoryIds = searchCategoryIds.Concat(allLinkedCategories).Distinct().ToArray(); } //Do not search in variations var query = repository.Items.Where(x => x.ParentId == null).Where(x => criteria.WithHidden ? true : x.IsActive); if (searchCategoryIds != null) { query = query.Where(x => searchCategoryIds.Contains(x.CategoryId) || x.CategoryLinks.Any(c => searchCategoryIds.Contains(c.CategoryId))); } else if (criteria.CatalogIds != null) { query = query.Where(x => criteria.CatalogIds.Contains(x.CatalogId) && (criteria.SearchInChildren || x.CategoryId == null)); } if (!string.IsNullOrEmpty(criteria.Code)) { query = query.Where(x => x.Code == criteria.Code); } else if (!string.IsNullOrEmpty(criteria.Keyword)) { query = query.Where(x => x.Name.Contains(criteria.Keyword) || x.Code.Contains(criteria.Keyword)); } //Filter by property dictionary values if (criteria.PropertyValues != null && criteria.PropertyValues.Any()) { var propValueIds = criteria.PropertyValues.Select(x => x.ValueId).Distinct().ToArray(); query = query.Where(x => x.ItemPropertyValues.Any(y => propValueIds.Contains(y.KeyValue))); } result.ProductsTotalCount = query.Count(); var itemIds = query.OrderByDescending(x => x.Name) .Skip(criteria.Skip) .Take(criteria.Take) .Select(x => x.Id) .ToArray(); var productResponseGroup = ItemResponseGroup.ItemInfo | ItemResponseGroup.ItemAssets | ItemResponseGroup.Links | ItemResponseGroup.Seo; if ((criteria.ResponseGroup & SearchResponseGroup.WithProperties) == SearchResponseGroup.WithProperties) { productResponseGroup |= ItemResponseGroup.ItemProperties; } if ((criteria.ResponseGroup & SearchResponseGroup.WithVariations) == SearchResponseGroup.WithVariations) { productResponseGroup |= ItemResponseGroup.Variations; } var products = _itemService.GetByIds(itemIds, productResponseGroup); result.Products = products.OrderByDescending(x => x.Name).ToList(); } }