public virtual async Task <ProductVariantAttributeCombination> FindAttributeCombinationAsync(int productId, ProductVariantAttributeSelection selection)
        {
            if (productId == 0 || !(selection?.AttributesMap?.Any() ?? false))
            {
                return(null);
            }

            var cacheKey = ATTRIBUTECOMBINATION_BY_IDJSON_KEY.FormatInvariant(productId, selection.AsJson());

            var combinations = await _requestCache.GetAsync(cacheKey, async() =>
            {
                var combinations = await _db.ProductVariantAttributeCombinations
                                   .AsNoTracking()
                                   .Where(x => x.ProductId == productId)
                                   .Select(x => new { x.Id, x.RawAttributes })
                                   .ToListAsync();

                foreach (var combination in combinations)
                {
                    if (selection.Equals(new ProductVariantAttributeSelection(combination.RawAttributes)))
                    {
                        return(await _db.ProductVariantAttributeCombinations.FindByIdAsync(combination.Id));
                    }
                }

                return(null);
            });

            return(null);
        }
        public virtual async Task <ProductVariantAttributeCombination> FindAttributeCombinationAsync(int productId, ProductVariantAttributeSelection selection)
        {
            // TODO: (core) (important) Save combination hash in table and always lookup by hash instead of iterating thru local data to find a match.

            if (productId == 0 || !(selection?.AttributesMap?.Any() ?? false))
            {
                return(null);
            }

            var cacheKey = ATTRIBUTECOMBINATION_BY_IDJSON_KEY.FormatInvariant(productId, selection.AsJson());

            var combination = await _requestCache.GetAsync(cacheKey, async() =>
            {
                var combinations = await _db.ProductVariantAttributeCombinations
                                   .AsNoTracking()
                                   .Where(x => x.ProductId == productId)
                                   .Select(x => new { x.Id, x.RawAttributes })
                                   .ToListAsync();

                foreach (var combination in combinations)
                {
                    if (selection.Equals(new ProductVariantAttributeSelection(combination.RawAttributes)))
                    {
                        return(await _db.ProductVariantAttributeCombinations.FindByIdAsync(combination.Id));
                    }
                }

                return(null);
            });

            return(combination);
        }