【问题标题】:Call a DTO translator inside IQueryable's Select在 IQueryable 的 Select 中调用 DTO 转换器
【发布时间】:2011-02-18 01:02:13
【问题描述】:

我有以下代码来查询 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)。

在这种情况下你会怎么做?

更新: 此外,我不想为完整的问题对象添加水分来做到这一点。我想依靠 Provider 创建 DTO 对象的能力。

【问题讨论】:

    标签: .net linq entity-framework iqueryable dto


    【解决方案1】:

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

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

    【讨论】:

    • 简单快速。无法要求更多。
    • 如果您的可查询对象尚未评估,这可能会导致不支持实例化新对象的提供程序出现异常。
    • 看来我应该多注意了
    【解决方案2】:

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

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

    这将导致查询转换为(本地)可枚举,在那里它可以安全地通过您的QuestionTranslator

    【讨论】:

    • 谢谢里德。由于您的回答,我觉得有必要更新问题。感谢您的尝试。
    【解决方案3】:

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

    【讨论】:

    • 感谢您的指点。当然强大,但我已经有一个提供程序,例如 EF。
    【解决方案4】:

    我使用 AutoMapper 从实体映射到 DTO,因为如果您为 Question 创建映射,那么它会自动知道如何映射 IEnumerable&lt;Question&gt;

    在一个语句中同时执行查询和映射的问题在于,当坏事发生时,它往往会导致您的数据映射器抛出难以破译的错误(很难判断问题是在查询执行中还是在映射中)

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

    【讨论】:

    • AutoMapper 是否像 Diego 建议的那样与 Expression> 一起工作?
    【解决方案5】:

    看到这个帖子:Autoprojecting LINQ queries

    当你使用它时,你会查询到:

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

    如果使用 NHibernate/EF,应该在服务器上发生(发送到 DB 的查询将仅具有预计的属性)。对于已经在内存中的对象(LINQ To Objects),应该仍然可以正常工作。

    【讨论】:

    • 非常有用的提示。正如 cmets 所指出的,这不是一个完整的解决方案,但可以工作。谢谢。
    • 只是强调一下,如果使用 NHibernate/EF,这应该发生在服务器上(发送到 DB 的查询将只具有预计的属性)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-15
    • 1970-01-01
    • 1970-01-01
    • 2012-06-12
    • 2018-06-01
    • 2012-08-06
    • 2012-02-07
    相关资源
    最近更新 更多