public GenericSearchResult <ListEntryBase> Search(CatalogListEntrySearchCriteria criteria) { var result = new GenericSearchResult <ListEntryBase>(); using (var repository = _catalogRepositoryFactory()) { //Optimize performance and CPU usage repository.DisableChangesTracking(); var query = repository.Categories.Where(cat => cat.CatalogId == criteria.CatalogId && cat.ParentCategoryId == criteria.CategoryId).Select(cat => new { cat.Id, cat.Name, cat.Code }) .Union(repository.Items.Where(item => item.CatalogId == criteria.CatalogId && item.CategoryId == criteria.CategoryId).Select(item => new { item.Id, item.Name, item.Code })); var sortInfos = criteria.SortInfos; if (sortInfos.IsNullOrEmpty()) { sortInfos = new[] { new SortInfo { SortColumn = "Name" } }; } query = query.OrderBySortInfos(sortInfos); result.TotalCount = query.Count(); var ids = query.Skip(criteria.Skip).Take(criteria.Take).Select(x => x.Id).ToList(); var productsListEntries = _itemService.GetByIds(ids, (ItemResponseGroup.ItemInfo | ItemResponseGroup.ItemAssets | ItemResponseGroup.Outlines).ToString()).Select(x => AbstractTypeFactory <ProductListEntry> .TryCreateInstance().FromModel(x)); var categoriesListEntries = _categoryService.GetByIds(ids, (CategoryResponseGroup.Info | CategoryResponseGroup.WithImages | CategoryResponseGroup.WithOutlines).ToString()).Select(x => AbstractTypeFactory <CategoryListEntry> .TryCreateInstance().FromModel(x));; result.Results = productsListEntries.Concat(categoriesListEntries).OrderBy(x => ids.IndexOf(x.Id)).ToList(); } return(result); }
public ActionResult ListItemsSearch([FromBody] CatalogListEntrySearchCriteria criteria) { //TODO: //ApplyRestrictionsForCurrentUser(coreModelCriteria); var result = _listEntrySearchService.Search(criteria); return(Ok(result)); }
public async Task <ListEntrySearchResult> SearchAsync(CatalogListEntrySearchCriteria criteria) { if (criteria == null) { throw new ArgumentNullException(nameof(criteria)); } criteria = criteria.Clone() as CatalogListEntrySearchCriteria; criteria.Normalize(); var result = AbstractTypeFactory <ListEntrySearchResult> .TryCreateInstance(); //Need search in children categories if user specify keyword if (!string.IsNullOrEmpty(criteria.Keyword)) { criteria.SearchInChildren = true; criteria.SearchInVariations = true; } var categorySkip = 0; var categoryTake = 0; //Because products and categories represent in search result as two separated collections for handle paging request //we should join two resulting collection artificially //search categories if (criteria.ObjectTypes.IsNullOrEmpty() || criteria.ObjectTypes.Contains(nameof(Category))) { var categoriesSearchResult = await SearchCategoriesAsync(criteria); var categoriesTotalCount = categoriesSearchResult.TotalCount; categorySkip = Math.Min(categoriesTotalCount, criteria.Skip); categoryTake = Math.Min(criteria.Take, Math.Max(0, categoriesTotalCount - criteria.Skip)); var categoryListEntries = categoriesSearchResult.Results.Select(x => AbstractTypeFactory <CategoryListEntry> .TryCreateInstance().FromModel(x)).ToList(); result.TotalCount = categoriesTotalCount; result.ListEntries.AddRange(categoryListEntries); } if (criteria.ObjectTypes.IsNullOrEmpty() || criteria.ObjectTypes.Contains(nameof(CatalogProduct))) { criteria.Skip -= categorySkip; criteria.Take -= categoryTake; var productsSearchResult = await SearchItemsAsync(criteria); var productListEntries = productsSearchResult.Results.Select(x => AbstractTypeFactory <ProductListEntry> .TryCreateInstance().FromModel(x)).ToList(); result.TotalCount += productsSearchResult.TotalCount; result.ListEntries.AddRange(productListEntries); } return(result); }
protected virtual IList <SortInfo> BuildSortExpression(CatalogListEntrySearchCriteria criteria) { var sortInfos = criteria.SortInfos; if (sortInfos.IsNullOrEmpty()) { sortInfos = new[] { new SortInfo { SortColumn = nameof(ItemEntity.Priority), SortDirection = SortDirection.Descending }, new SortInfo { SortColumn = nameof(CategoryEntity.Name) } }; } return(sortInfos); }
private async Task <ListEntrySearchResult> InnerListItemsSearchAsync(CatalogListEntrySearchCriteria criteria) { var result = new ListEntrySearchResult(); var useIndexedSearch = _settingsManager.GetValue(ModuleConstants.Settings.Search.UseCatalogIndexedSearchInManager.Name, true); if (useIndexedSearch && !string.IsNullOrEmpty(criteria.Keyword)) { // TODO: create outline for category // TODO: implement sorting var categoryIndexedSearchCriteria = AbstractTypeFactory <CategoryIndexedSearchCriteria> .TryCreateInstance().FromListEntryCriteria(criteria) as CategoryIndexedSearchCriteria; const CategoryResponseGroup catResponseGroup = CategoryResponseGroup.Info | CategoryResponseGroup.WithOutlines; categoryIndexedSearchCriteria.ResponseGroup = catResponseGroup.ToString(); var catIndexedSearchResult = await _categoryIndexedSearchService.SearchAsync(categoryIndexedSearchCriteria); var totalCount = catIndexedSearchResult.TotalCount; var skip = Math.Min(totalCount, criteria.Skip); var take = Math.Min(criteria.Take, Math.Max(0, totalCount - criteria.Skip)); result.Results = catIndexedSearchResult.Items.Select(x => AbstractTypeFactory <CategoryListEntry> .TryCreateInstance().FromModel(x)).ToList(); criteria.Skip -= (int)skip; criteria.Take -= (int)take; const ItemResponseGroup itemResponseGroup = ItemResponseGroup.ItemInfo | ItemResponseGroup.Outlines; var productIndexedSearchCriteria = AbstractTypeFactory <ProductIndexedSearchCriteria> .TryCreateInstance().FromListEntryCriteria(criteria) as ProductIndexedSearchCriteria; productIndexedSearchCriteria.ResponseGroup = itemResponseGroup.ToString(); var indexedSearchResult = await _productIndexedSearchService.SearchAsync(productIndexedSearchCriteria); result.TotalCount += (int)indexedSearchResult.TotalCount; result.Results.AddRange(indexedSearchResult.Items.Select(x => AbstractTypeFactory <ProductListEntry> .TryCreateInstance().FromModel(x))); } else { result = await _listEntrySearchService.SearchAsync(criteria); } return(result); }
public async Task <ActionResult> Delete([FromBody] CatalogListEntrySearchCriteria criteria) { const int deleteBatchSize = 20; var authorizationResult = await _authorizationService.AuthorizeAsync(User, criteria, new CatalogAuthorizationRequirement(ModuleConstants.Security.Permissions.Delete)); if (!authorizationResult.Succeeded) { return(Unauthorized()); } var idsToDelete = criteria.ObjectIds?.ToList() ?? new List <string>(); if (idsToDelete.IsNullOrEmpty()) { var listEntries = await InnerListItemsSearchAsync(criteria); idsToDelete = listEntries.ListEntries .Where(x => x.Type.EqualsInvariant(ProductListEntry.TypeName) || x.Type.EqualsInvariant(CategoryListEntry.TypeName)) .Select(x => x.Id) .ToList(); } for (var i = 0; i < idsToDelete.Count; i += deleteBatchSize) { var commonIds = idsToDelete.Skip(i).Take(deleteBatchSize).ToArray(); var searchProductResult = await _itemService.GetByIdsAsync(commonIds, ItemResponseGroup.None.ToString()); await _itemService.DeleteAsync(searchProductResult.Select(x => x.Id).ToArray()); var searchCategoryResult = await _categoryService.GetByIdsAsync(commonIds, CategoryResponseGroup.None.ToString()); await _categoryService.DeleteAsync(searchCategoryResult.Select(x => x.Id).ToArray()); } return(StatusCode(StatusCodes.Status204NoContent)); }
protected virtual async Task <GenericSearchResult <Category> > SearchCategoriesAsync(CatalogListEntrySearchCriteria criteria) { var result = new GenericSearchResult <Category>(); using (var repository = _catalogRepositoryFactory()) { //Optimize performance and CPU usage repository.DisableChangesTracking(); 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(await repository.GetAllChildrenCategoriesIdsAsync(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(await repository.GetAllChildrenCategoriesIdsAsync(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); } //Extension point query = BuildQuery(query, criteria); var sortInfos = BuildSortExpression(criteria); //Try to replace sorting columns names TryTransformSortingInfoColumnNames(_categorySortingAliases, sortInfos); result.TotalCount = await query.CountAsync(); if (criteria.Take > 0 && result.TotalCount > 0) { query = query.OrderBySortInfos(sortInfos).ThenBy(x => x.Id); var categoryIds = query.Select(x => x.Id).AsNoTracking().ToList(); var essentialResponseGroup = CategoryResponseGroup.Info | CategoryResponseGroup.WithImages | CategoryResponseGroup.WithSeo | CategoryResponseGroup.WithLinks | CategoryResponseGroup.WithParents | CategoryResponseGroup.WithProperties | CategoryResponseGroup.WithOutlines; var respGroup = string.Concat(criteria.ResponseGroup, ",", essentialResponseGroup.ToString()); result.Results = (await _categoryService.GetByIdsAsync(categoryIds.ToArray(), respGroup, criteria.CatalogId)).OrderBy(x => categoryIds.IndexOf(x.Id)).ToList(); } } return(result); }
protected virtual IQueryable <ItemEntity> BuildQuery(IQueryable <ItemEntity> query, CatalogListEntrySearchCriteria criteria, string[] searchCategoryIds) { query = query.Where(x => criteria.WithHidden || x.IsActive); if (!string.IsNullOrEmpty(criteria.MainProductId)) { query = query.Where(x => x.ParentId == criteria.MainProductId); } else if (!criteria.SearchInVariations) { query = query.Where(x => x.ParentId == null); } if (!searchCategoryIds.IsNullOrEmpty()) { query = query.Where(x => searchCategoryIds.Contains(x.CategoryId) || x.CategoryLinks.Any(link => searchCategoryIds.Contains(link.CategoryId))); } else if (!criteria.CatalogIds.IsNullOrEmpty()) { query = query.Where(x => criteria.CatalogIds.Contains(x.CatalogId) && (criteria.SearchInChildren || x.CategoryId == null) || x.CategoryLinks.Any(link => criteria.CatalogIds.Contains(link.CatalogId) && (criteria.SearchInChildren || link.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)); } if (!criteria.VendorIds.IsNullOrEmpty()) { query = query.Where(x => criteria.VendorIds.Contains(x.Vendor)); } 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); } return(query); }
protected virtual IQueryable <CategoryEntity> BuildQuery(IQueryable <CategoryEntity> query, CatalogListEntrySearchCriteria criteria) { return(query); }
protected virtual async Task <GenericSearchResult <CatalogProduct> > SearchItemsAsync(CatalogListEntrySearchCriteria criteria) { var result = new GenericSearchResult <CatalogProduct>(); using (var repository = _catalogRepositoryFactory()) { //Optimize performance and CPU usage repository.DisableChangesTracking(); //list of search categories var searchCategoryIds = criteria.CategoryIds; if (criteria.SearchInChildren) { if (!searchCategoryIds.IsNullOrEmpty()) { searchCategoryIds = searchCategoryIds.Concat(await repository.GetAllChildrenCategoriesIdsAsync(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(); } } // Build the query based on the search criteria var query = BuildQuery(repository.Items, criteria, searchCategoryIds); var sortInfos = BuildSortExpression(criteria); //Try to replace sorting columns names TryTransformSortingInfoColumnNames(_productSortingAliases, sortInfos.ToArray()); result.TotalCount = await query.CountAsync(); if (criteria.Take > 0 && result.TotalCount > 0) { query = query.OrderBySortInfos(sortInfos).ThenBy(x => x.Id); var itemIds = query.Skip(criteria.Skip) .Take(criteria.Take) .Select(x => x.Id) .AsNoTracking() .ToList(); var essentialResponseGroup = ItemResponseGroup.ItemInfo | ItemResponseGroup.ItemAssets | ItemResponseGroup.Links | ItemResponseGroup.Seo | ItemResponseGroup.Outlines; var responseGroup = string.Concat(criteria.ResponseGroup, ",", essentialResponseGroup.ToString()); result.Results = (await _itemService.GetByIdsAsync(itemIds.ToArray(), responseGroup, criteria.CatalogId)).OrderBy(x => itemIds.IndexOf(x.Id)).ToList(); } } return(result); }
public async Task <ActionResult <ListEntrySearchResult> > ListItemsSearchAsync([FromBody] CatalogListEntrySearchCriteria criteria) { var authorizationResult = await _authorizationService.AuthorizeAsync(User, criteria, new CatalogAuthorizationRequirement(ModuleConstants.Security.Permissions.Read)); if (!authorizationResult.Succeeded) { return(Unauthorized()); } var result = await InnerListItemsSearchAsync(criteria); return(Ok(result)); }
public async Task <ActionResult <ListEntrySearchResult> > ListItemsSearchAsync([FromBody] CatalogListEntrySearchCriteria criteria) { //TODO: //ApplyRestrictionsForCurrentUser(coreModelCriteria); var result = new ListEntrySearchResult(); var useIndexedSearch = _settingsManager.GetValue(ModuleConstants.Settings.Search.UseCatalogIndexedSearchInManager.Name, true); if (useIndexedSearch && !string.IsNullOrEmpty(criteria.Keyword)) { // TODO: create outline for category // TODO: implement sorting const ItemResponseGroup responseGroup = ItemResponseGroup.ItemInfo | ItemResponseGroup.Outlines; var productIndexedSearchCriteria = AbstractTypeFactory <ProductIndexedSearchCriteria> .TryCreateInstance(); productIndexedSearchCriteria.ObjectType = KnownDocumentTypes.Product; productIndexedSearchCriteria.Keyword = criteria.Keyword; productIndexedSearchCriteria.CatalogId = criteria.CatalogId; productIndexedSearchCriteria.Outline = criteria.CategoryId; productIndexedSearchCriteria.WithHidden = !criteria.HideDirectLinkedCategories; productIndexedSearchCriteria.Skip = criteria.Skip; productIndexedSearchCriteria.Take = criteria.Take; productIndexedSearchCriteria.ResponseGroup = responseGroup.ToString(); productIndexedSearchCriteria.Sort = criteria.Sort; var indexedSearchResult = await _productIndexedSearchService.SearchAsync(productIndexedSearchCriteria); result.TotalCount = (int)indexedSearchResult.TotalCount; result.Results = indexedSearchResult.Items.Select(x => AbstractTypeFactory <ProductListEntry> .TryCreateInstance().FromModel(x)).ToList(); } else { result = await _listEntrySearchService.SearchAsync(criteria); } return(Ok(result)); }