Позвоните переводчику DTO в IQueryable's Select - PullRequest
2 голосов
/ 18 февраля 2011

У меня есть следующий код для запроса EntityContext (через репозиторий) и сопоставления его с DTO:

public class QueryQuestionsConsumer : IConsumerOf<QueryQuestionsRequest>
{
    public void Consume(QueryQuestionsRequest request)
    {
        var repo = IoC.Resolve<IUnitOfWork>().CreateRepository<Question>();
        var filter = FilterTranslator.CreateFilterExpression<Question>(request.Filters);
        var questions = repo
            .GetAll()
            .Where(filter)

        Result = questions.Select(question => QuestionTranslator.ToDTO(question)).ToArray()
    }

}

Это, очевидно, не получится, потому что ToDTO () не распознается функцией в провайдере EntityFramework. Я мог бы создать объект DTO, используя инициализатор объекта, но я бы хотел делегировать его другому классу (QuestionTranslator).

Что вы делаете в этом случае?

ОБНОВЛЕНИЕ: Кроме того, я не хочу увлажнять полный Объект Вопроса, чтобы сделать это. Я хотел бы рассчитывать на способность Провайдера создавать объекты DTO.

Ответы [ 5 ]

3 голосов
/ 18 февраля 2011

Помимо очевидного варианта использования questions.AsEnumerable().Select(...), чтобы заставить EF извлекать полные записи и затем отображать их на стороне клиента, вы можете заставить свой метод ToDTO возвращать выражение:

Expression<Func<Question, QuestionDTO>> ToDTO()
{
    Expression<Func<Question, QuestionDTO>> exp =
        question => new QuestionDTO { ... };
    return exp;
}
1 голос
/ 18 февраля 2011

Вы можете преобразовать его в перечисляемый, а затем перевести локально:

Result = questions.AsEnumerable()
                  .Select(question => QuestionTranslator.ToDTO(question)).ToArray()

Это приведет к тому, что запрос будет преобразован в (локальный) перечислимый, где его можно безопасно пропустить через QuestionTranslator.

0 голосов
/ 18 февраля 2011

См. Этот пост: Автопроектирование запросов LINQ .

Когда вы его используете, запрос будет выглядеть так:

        Result = questions.Project().To<QuestionDto>().ToArray()

Должно произойти на серверепри использовании NHibernate / EF (запрос, отправленный в БД, будет иметь только спроецированные свойства).Должен по-прежнему нормально работать с объектами, считанными в памяти (LINQ To Objects).

0 голосов
/ 18 февраля 2011

Я использую AutoMapper для сопоставления сущностей с DTO, потому что если вы создадите сопоставление для Question, тогда оно автоматически узнает, как сопоставлять IEnumerable<Question>

Проблема с выполнением запроса и сопоставления в одномУтверждение состоит в том, что это приводит к тому, что ваш datamapper изо всех сил старается расшифровать ошибки, когда происходят плохие вещи (трудно сказать, была ли проблема в выполнении запроса или в отображении)

Мне было гораздо проще следовать«запустить» запрос, выполнив .ToList()/.AsEnumerable() и т. д., а затем передать эту переменную мапперу.Это позволяет исключениям быть очень ясными при возникновении проблем, и становится ясно, была ли проблема в запросе или в отображении.

0 голосов
/ 18 февраля 2011

Существует большая серия блогов, в которых объясняется, как реализовать этот тип функций без принудительной оценки запроса.Это в основном зависит от реализации IQueryProvider.Это не тривиальная задача, и следующая ссылка дает отличный пример построения.http://blogs.msdn.com/b/mattwar/archive/2008/11/18/linq-links.aspx

...