Return products which belong to all tags in a list

2019-08-03 22:36发布

问题:

I have a service method which accepts a delimited list of tags and is supposed to return a list of products which are assigned to all tags in that list.

This is what I have, and it returns no products. I've double-checked the data, there IS a product that belongs to two tags.

public List<Product> GetTagProducts(string tags)
{
    //list of parameters
    var tagParams = tags.Split('+').ToList();

    //return all products which belong to ALL tags specified in tagParams list
    return (from pt in _repository.ProductTags
            where tagParams.All(p => p == pt.Tag.Name)
            select pt.Product).Distinct().Take(75).ToList();
}

public class Tag
{
    [Key]
    public int TagId { get; set; }
    public string Name { get; set; }

    public virtual List<Product> Products { get; set; }
    public virtual List<ProductTag> ProductTags { get; set; }

}

public class Product
{
    public int ProductId { get; set; }
    [Required]
    [Display(Name = "Name")]
    public string Name { get; set; }
    [Required]
    [Display(Name = "Short Description")]
    public string ShortDescription { get; set; }
    [Required]
    [Display(Name = "Long Description")]
    public string LongDescription { get; set; }
    [Required]
    [Display(Name = "Price")]
    public decimal Price { get; set; }

    public virtual List<Tag> Tags { get; set; }
}

public class ProductTag
{
    [Key]
    public int ProductTagId { get; set; }
    [ForeignKey("Product")]
    public int ProductId { get; set; }
    [ForeignKey("Tag")]
    public int TagId { get; set; }

    public virtual Product Product { get; set; }
    public virtual Tag Tag { get; set; }
}

//Repository
private DatabaseContext _context = new DatabaseContext();
public IQueryable<ProductTag> ProductTags
    {
        get { return _context.ProductTags; }
    }



EDIT: to clarify the result I'm looking for. Lets say tagParams holds two tag strings (meaning I am searching for products tagged with BOTH of these):

Automotive
General

And lets say we have the following products:

product             tags
-------             ----
Wipers              Automotive, General
Air Freshener       General
Gloves              General
Tires               Automotive
Mirror              Automotive, General

The query should return "Wipers" and "Mirror".

回答1:

Method chain style:

List<Product> allProducts = GetAllProductsFromSomewhere();
allProducts.Where(p => tagParams.All(tag => 
p.Tags.Select(x => x.Name).Contains(tag))).Distinct().Take(75).ToList();

All means that all of the tags should equal to one tag. And you said it contains two tags, So it's impossible.
In MSDN words:

Determines whether all elements of a sequence satisfy a condition.