Фильтрация коллекций в Entity Framework 4 - PullRequest
4 голосов
/ 01 июля 2010

Я тестировал EF 4 и собираюсь отфильтровать дочерние коллекции для объекта.

Я использую поддержку POCO, и EF автоматически подключает мои коллекции:

        public virtual ICollection<Product> Products { get; set; }

Таким образом, в этом примере я могу получить экземпляр категории и затем перечислить ее продукты.

Что я хочу знать, так это то, как я могу затем отфильтровать эту коллекцию, скажем, для возврата только активных продуктов.Я знаю, что могу сделать это в памяти, но важно, чтобы критерии отправлялись непосредственно в базу данных.

В NHibernate я могу сделать это, используя фильтры в моей коллекции, есть ли что-то эквивалентное в EF 4?

Я действительно думал о создании другой коллекции, например

public virtual ICollection<Product> ActiveProducts {get;set;} 

, но не уверен, как потом подключить это.

Спасибо, Бен

Ответы [ 2 ]

1 голос
/ 17 июля 2010

Я знаю простой обходной путь, не очень аккуратный (ИМХО)

var idCategory = *get from somewhere*;
var db = new MyContext();
var activeProducts = db.Products.ActiveByCategory(idCategory);

и расширение выглядит примерно так

public static class Extensions {
    public static IQueryable<Product> ActiveByCategory(this IQueryable<Product> source, int idCategory) {
        return source.Where(p => p.CategoryId == idCategory && p.Active);
    }
}

бедно, но надеюсь, что все равно поможет

EDIT:

другой способ это

var activeProducts = db.Categories.Where(c => c.Id == idCategory).SelectMany(c => c.Products).Where(p => p.Active);

сгенерированный запрос:

SELECT 
[Extent1].[CategoryId] AS [CategoryId], 
[Extent1].[Id] AS [Id], 
[Extent1].[Name] AS [Name]
[Extent1].[Active] AS [Active]
FROM [dbo].[Products] AS [Extent1]
WHERE (2 = [Extent1].[CategoryId]) AND ([Extent1].[Active] = 'true')

2 = idCategory

1 голос
/ 16 июля 2010

К сожалению, это официально невозможно с текущей версией Entity Framework. Я провел некоторое время, погружаясь в эту проблему сам. Я вполне уверен, что вы могли бы заставить его работать с некоторым основанным на отражении кодом, в котором вы изменили бы поведение по умолчанию, но я думаю, что это будет несколько сложнее.

Я вряд ли являюсь экспертом DDD, но я думаю, что более правильный способ сделать это - использовать определенный запрос для получения активных Продуктов, для которых задана сущность типа вашего содержащего класса. Вы можете найти это либо в хранилище, либо в классе запросов. Если вам необходимо запретить другим пользователям доступ к этому свойству по соображениям эффективности (как в моем случае), вы, вероятно, захотите удалить его из класса сущностей и сделать свой запрос единственным способом доступа к активным продуктам.

Если вы все еще хотите выполнить фильтрацию коллекции на стороне базы данных, я предлагаю переопределить поле делегата, которое имеют прокси-классы для каждого свойства. Если вы возьмете пример кода из этого поста в блоге , просматривая сгенерированный источник прокси и используете Reflector от RedGate, вы увидите поля, о которых я говорю. Это будут частные статические делегаты Func <[ProxyType], [PropertyType], [bool]> с именами ef_proxy_interceptorFor [PropertyName]. Возвращаемое значение будет определять, возвращает ли получатель значение свойства вашего базового класса или объект, переданный делегату (false для первого, true для последнего).

...