Web Api 2 + EF6 - 构建DTO

时间:2015-06-17 10:21:35

标签: c# entity-framework asp.net-web-api

对于一个项目,我们正在使用EF和Web Api 2.为了从我们的数据库模型中抽象出来,我们正在使用DTO' s。我们有一家工厂来建造这些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无法处理创建功能。

我也愿意采用其他方式与DTO合作,有更好的方法可以做到这一点,还是没有办法避免额外传递所有查询结果?

哦,抓住了,我想这样做没有 automapper。

1 个答案:

答案 0 :(得分:5)

首先,它似乎更像是一个代码审查问题。 我建议你不要在控制器中直接使用实体框架(代码中的db)。控制器应该很薄,查询逻辑可能非常复杂。在许多情况下,您需要从数据库中查询无法映射到实体的数据。因此,您可以创建直接返回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();
       } 
   }
}

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

注意:等待是必要的 - 不能直接在这里返回任务。