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

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

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

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.

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

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

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

1 Ответ

3 голосов
/ 25 марта 2020

Поскольку вы не переопределили 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 из Product:

_Customers = await _context.Customers.SelectMany(c => c.orders.SelectMany(o => o.Products
              .Where(p => DiscountItems.Contains(p, new ItemComparer()))))
              .ToListAsync();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...