对于一个项目,我们正在使用 EF 和 Web Api 2。为了从我们的数据库模型中抽象出来,我们正在使用 DTO。我们有一个工厂来构建这些 DTO:

public class FooFactory:IModelConverter<FooDTO, Foo>
{

    public FooDTO Create(Foo data)
    {
        return new FooDTO()
        {
           //Some fields
        };
    }
}

在我们的 Api 调用中,我们可以执行以下操作:
public async Task<IHttpActionResult> GetFoo()
    {
        var foos = db.Foos

        //DO STUFF

         var dtos = (await foos.ToListAsync()).Select(m => _converter.Create(m)); //Converter is an instance of FooFactory)

        return Ok(dtos);
    }

这有效,但意味着,在我们执行查询后,我们必须遍历所有结果并将每个模型转换为 DTO。

另一方面,我们可以这样做:
public async Task<IHttpActionResult> GetFoo()
    {
        var foos = db.Foos

        //DO STUFF

        return Ok(await foos.Select(m => new FooDTO() {
            //Assign fields
        }).ToListAsync());
    }

这会将这个投影集成到 EF 执行的查询中。但这暴露了 FooDTO 的所有内部细节,我们必须重复所有这些创建代码。

有没有办法做这样的事情:
public async Task<IHttpActionResult> GetFoo()
    {
        var foos = db.Foos

        //DO STUFF

        return Ok(await foos.Select(m => _converter.Create(m)).ToListAsync());
    }

这不起作用,因为 Linq to Entities 无法处理 create 函数。

我也对使用 DTO 的其他方法持开放态度,有没有更好的方法来做到这一点,或者有没有办法避免额外传递所有查询结果?

哦,问题是,我想在没有 自动映射器的情况下执行 操作。

最佳答案

首先,它看起来更像是一个代码审查问题。
我建议您不要直接在 Controller 中使用 Entity Framework (代码中的 db)。 Controller 应该是瘦的,查询逻辑可以非常复杂。在很多情况下,您需要从无法映射到实体的数据库中查询数据。因此,您可以创建直接返回 DTO 的存储库类:

class FooRepository
{
   public async Task<List<FooDTO>> FindAsync()
   {
       using(var context = new DbContext())
       {
           return await context.Foos
               .Select(m => new FooDTO
               {
                   Id = m.Id,
                   ...
               })
               .ToListAsync();
       }
   }
}

这种方法的另一个优点是您只查询真正需要的数据,现在查询整个实体。

注意:await 是必须的——这里不能直接返回 Task。

关于c# - Web Api 2 + EF6 - 构建 DTO,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30888764/

10-14 10:53