在IQueryable的Select中调用DTO翻译器

时间:2011-02-18 01:02:14

标签: .net linq entity-framework iqueryable dto

我有以下代码来查询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 个答案:

答案 0 :(得分:3)

除了使用questions.AsEnumerable().Select(...)强制EF检索完整记录然后将其映射到客户端的明显选项之外,您还可以使ToDTO方法返回表达式:

Expression<Func<Question, QuestionDTO>> ToDTO()
{
    Expression<Func<Question, QuestionDTO>> exp =
        question => new QuestionDTO { ... };
    return exp;
}

答案 1 :(得分:1)

您可以将其转换为可枚举,然后在本地进行翻译:

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

这将导致查询转换为(本地)可枚举,可以安全地通过QuestionTranslator传递查询。

答案 2 :(得分:0)

有一个很棒的博客系列解释了如何在不强制评估查询的情况下实现此类功能。它基本上依赖于实现IQueryProvider。这不是一项微不足道的任务,以下链接提供了一个很好的案例研究。 http://blogs.msdn.com/b/mattwar/archive/2008/11/18/linq-links.aspx

答案 3 :(得分:0)

我使用AutoMapper从实体映射到DTO,因为如果您为Question创建映射,那么它将自动知道如何映射IEnumerable<Question>

在一个语句中同时执行查询和映射的问题是,当发生错误时,它往往会导致数据管理器难以解密错误(很难判断问题是在查询执行中还是在映射中)

我发现通过执行.ToList()/.AsEnumerable()等来“触发”查询更容易,然后将该变量传递给映射器。这允许在出现问题时非常清楚异常,从而清楚问题是在查询中还是在映射中。

答案 4 :(得分:0)

请参阅此帖:Autoprojecting LINQ queries

当您使用它时,您将查询如下:

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

如果使用NHibernate / EF,则应该在服务器上发生(发送到DB的查询只有预计的属性)。应该仍能正常处理内存中的对象(LINQ To Objects)。