Фильтрация родительского объекта по связанному объекту, 2 уровня глубины

Я ищу способ фильтровать мой набор базовых объектов, проверяя, является ли объект «внука» членом списка объектов того же типа.

Например, у меня есть следующие классы:

public class Customer
{
     public int Id { get; set; }
     public string Name { get; set; }
     public virtual ICollection<Order> orders { get; set; }
}

public class Order
{
     public int Id { get; set; }
     public Datetime OrderDate { get; set; }
     public virtual Customer Customer { get; set; }
     public virtual ICollection<Product> Products { get; set; }
}

public class Product
{
     public int Id { get; set; }
     public int DepartmentID { get; set; }
     public string Name { get; set; }
     public string Description { get; set; }
}

У меня есть список Products , может быть, что-то особенное в них, например, если к ним применена скидка:

List<Product> DiscountItems = new List<Product>();
{
     new Product { Id = 0, DepartmentID = 2, Name = "Widget1", Description = "Big widget" },  
     new Product { Id = 1, DepartmentID = 2, Name = "Widget2", Description = "Medium widget" },  
     new Product { Id = 2, DepartmentID = 4, Name = "Widget3", Description = "Small widget" }  
};  

Я хотел бы использовать LINQ (или другое элегантное решение) для создания Коллекции / Списка клиентов (вместе со связанными Заказами и связанными продуктами), которые разместили заказы с использованием Продуктов, которые указаны в этом списке DiscountItems .

Я попробовал много вариантов в моем утверждении, но безуспешно. Вот пример того, что я хотел бы сделать (не работает, псевдо-код):

_Customers = await _context.Customers.Select(c => c.orders.Select(o => o.Products
                 .Where(p => DiscountItems.Contains(p)))).ToListAsync();

Ваша помощь и руководство очень ценятся.

Всего 1 ответ


Поскольку вы не переопределили Equals и GetHashCode() в своем классе Product или не реализовали IEqualityComparer<Product> вы просто получаете сравнение по умолчанию, которое проверяет, равны ли ссылки. Так что вам нужно что-то вроде этого:

class ItemComparer : IEqualityComparer<Product>
{

    public bool Equals(Product x, Product y)
    {
        return x.Id == y.Id &&
            x.Name == y.Name &&
            x.DepartmentID == y.DepartmentID &&
            x.Description == y.Description;
    }

    public int GetHashCode(Product obj)
    {
        return obj.Id.GetHashCode() ^
            obj.Name.GetHashCode() ^
            obj.DepartmentID.GetHashCode() ^
            obj.Description.GetHashCode();
    }
}

Затем вы можете добавить новый компаратор в ваш метод Contains точно так же, как это, и получить желаемые результаты:

_Customers = await _context.Customers.Select(c => c.orders.Select(o => o.Products
       .Where(p => DiscountItems.Contains(p, new ItemComparer()))))
       .ToListAsync();

Также вы можете использовать SelectMany вместо Select в этом случае, чтобы сгладить ваш список и просто получить List Product в результате вместо получения List IEnumerable IEnumerable of Product :

_Customers = await _context.Customers.SelectMany(c => c.orders.SelectMany(o => o.Products
              .Where(p => DiscountItems.Contains(p, new ItemComparer()))))
              .ToListAsync();