0

У меня есть следующий метод в классе доступа к данным, который использует рамки сущности:Передача запроса GetWhere (Func <entityDTO, BOOL>) к методу слоя данных, который нуждается в (Func <entity,bool>) параметр для работы

public static IEnumerable<entityType> GetWhere(Func<entityType, bool> wherePredicate) 
{ 
    using (DataEntities db = new DataEntities()) 
    { 
     var query = (wherePredicate != null) 
      ? db.Set<entityType>().Where(wherePredicate).ToList() 
      : db.Set<entityType>().ToList();      
     return query; 
    } 
} 

Это прекрасно работает, когда я использую объекты во всех слоях ... однако я пытаюсь перейти к использованию класса DTO, и я хотел бы сделать что-то вроде следующего:

public static IEnumerable<EntityTypeDTO> GetWhere(Func<EntityTypeDTO, bool> wherePredicate) 
{ 
    //call a method here which will convert Func<EntityTypeDTO,bool> to 
    // Func<EntityType,bool> 

    using (DataEntities db = new DataEntities()) 
    { 
     var query = new List<EntityType>(); 
     if (wherePredicate == null) 
     { 
      query = db.Set<EntityType>().ToList(); 
     } 
     else 
     { 
      query = (wherePredicate != null) 
       ? db.Set<EntityType>().Where(wherePredicate).AsQueryable<EntityType>().ToList() 
       : db.Set<EntityType>().ToList(); 
     } 
     List<EntityTypeDTO> result = new List<EntityTypeDTO>(); 
     foreach(EntityType item in query) 
     { 
      result.Add(item.ToDTO()); 
     } 

     return result; 
    } 
} 

по существу я хочу метод который преобразует Func в Func.

Я думаю, что мне нужно разбить Func в дерево выражений, а затем как-то перестроить его в entityType?

Я хочу сделать это, чтобы позволить уровню презентации просто передать запросы выражения?

У меня отсутствует что-то базовое или есть более простой шаблон проектирования, который может передавать запрос от DTO до класса доступа к данным, не зная деталей запроса?

Я попытался сделать DTO наследованием от сущности, которая тоже не работает?

Если есть лучший шаблон дизайна, что мне не хватает, я хотел бы указатель и я могу исследовать оттуда ...

ответ

2

Во-первых, я хотел бы предложить, что вы положили запрашивая слой самостоятельно перед Entity Framework, а не позволять любому произвольному Func быть переданным, потому что в будущем будет очень легко передать Func, который Entity Framework не может перевести в оператор SQL (он может только переводить выражениями - основы в порядке, но если ваше выражение вызывает метод C#, например, тогда, скорее всего, не будет работать Entity Framework).

Таким образом, ваш слой поиска может иметь классы, которые вы создаете в качестве критериев (например, класс поиска ContainsName или класс ProductHasId), которые затем переводятся в выражения в вашем поисковом слое. Это полностью отделяет ваше приложение от ORM, что означает, что детали ORM (например, сущности или, например, ограничения того, что Funcs может и не может перевести), не просачиваются. Там много чего было написано об этом.

одно замечание, хотя, если вы являются работать близко к ОРМ слоя, Entity Framework очень умный, и вы, вероятно, может получить длинный путь, не пытаясь перевести Func < DTO, BOOL > к Func < entity, bool >. Например, в приведенном ниже коде доступ к «context.Products» возвращает «DbSet», и вызов Select on возвращает идентификатор IQueryable и вызов Where at the также возвращает IQueryable.Entity Framework переводит все из этого в один оператор SQL, так что не будет вытащить все остальные Продукты в память, а затем отфильтровать идентификатор в этом наборе памяти, он фактически выполнит фильтрацию в SQL, хотя фильтр работающий на проектируемый типе (что эквивалентно DTO в вашем случае), а не Entity Framework объект -

var results = context.Products 
    .Select(p => new { ID = p.ProductID, Name = p.ProductName }) 
    .Where(p => p.ID < 10) 
    .ToList(); 

SQL, исполненный:

SELECT 
    [Extent1].[ProductID] AS [ProductID], 
    [Extent1].[ProductName] AS [ProductName] 
FROM [dbo].[Products] AS [Extent1] 
WHERE [Extent1].[ProductID] < 10 

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

return context.Products 
    .Map<Product, ProductDTO()>() 
    .Where(productDtoWherePredicate) 
    .ToList(); 

.. тогда вы можете быть в порядке с Funcs, который у вас уже есть. Я предполагаю, что у вас уже есть какие-то функции отображения, чтобы получить от объектов EF до DTO (но если нет, то вам может понадобиться заглянуть в AutoMapper, чтобы помочь вам, - которая имеет поддержку «прогнозов», которые в основном представляют собой карты IQueryable).

0

Я собираюсь выразить это как ответ. Спасибо Дэн за быстрый ответ. Глядя на то, что вы говорите, я могу написать набор запросов/фильтров. например, принять следующий код:

GetProducts().GetProductsInCategory().GetProductsWithinPriceRange(minPrice, maxPrice); 

Этот код будет работать следующим образом: Получить продукты будет получить все продукты в таблице, а остальные функции будут фильтровать результаты. если все запросы выполняются, как это, это может привести к значительной нагрузке на соединения Access Access Layer/DB Server Connections ... не уверен.

или

Альтернативный Я буду работать над также: Если каждая функция создает выражение Linq, я мог бы объединить их так: How do I combine multiple linq queries into one results set? это может позволить мне сделать это в манере, где я могу вернуться отфильтрованные результаты, установленные из базы данных.

В любом случае я отмечаю это как ответ. Я уточню, когда у меня появятся дополнительные сведения.

+0

Если GetProducts возвращает IQueryable , а не IEnumerable и как GetProductsInCategory и GetProductsWithinPriceRange принимают и возвращают IQueryable экземпляров затем Entity Framework будет иметь возможность принять все эту работу и превратить его в одном оператор SQL означает, что фильтрация все сделано в базе данных и НЕ в памяти в вашем уровне доступа. Когда вы фильтруете IEnumerable , тогда вы делаете это в памяти, но пока вы работаете над IQueryable , работа может быть загружена в базу данных. –

+0

Для вашего плана B возникнут некоторые сложности при объединении ваших критериев - вы хотите, чтобы каждый из них был выражением >, а не только Func , чтобы EF мог перевести их в SQL (и не нужно делать фильтрацию всей встроенной памяти, что, вероятно, потребует вытащить гораздо больше данных из db, чем это необходимо). Вот пример кода в ответе, который я оставил по другому вопросу, который должен помочь: http://stackoverflow.com/a/37907316/3813189 –