我正在创建一个MS Web API 2项目。我在一个单独的项目中创建了我的实体框架,并在我的API中引用它。阅读一些教程,建议:
"理想情况下,我们不应该从Web API返回EF实体对象。建议从Web API"。
返回DTO(数据传输对象)因此,我在我的API中创建了我的模型:
namespace MyAPI.Models
{
[Table("Customer")]
public class CustomerViewModel
{
[Key]
public int CustomerID { get; set; }
public string Code { get; set; }
public string Name { get; set; }
}
}
我的问题是:我是否需要为我的API中的每个模型创建一个数据上下文类,或者使用EF上下文类是否合适?如果我确实需要创建一个单独的上下文每个模型,如何通过引用EF上下文类来实现这一目标?以下是我的开始:
namespace MyAPI.Models
{
public class CustomerDbContext : DbContext
{
public CustomerDbContext() : base("name=CusetomerDbContext")
{
}
public DbSet<MyEFDataAccess.Customer> CustomerViewModel { get; set; }
}
}
我的控制器是:
namespace MyAPI.Controllers
{
public class CustomersController : ApiController
{
private readonly CustomerDbContext _context = new CustomerDbContext();
// GET: api/Customer
public IQueryable<CustomerViewModel> GetCustomerViewModels()
{
return _context.CustomerViewModel;
}
}
以上正确抛出错误,因为它无法直接将EF客户转换为CustomerViewModel!
答案 0 :(得分:3)
理想情况下,我们不应该从Web API返回EF实体对象。它 建议从Web API返回DTO(数据传输对象)。
这样做的原因是为了确保您可以在不更改API的情况下更改数据库架构,反之亦然。如果你实现了这个目标,那么你就已经遵守了这个建议。
你遇到的问题是基本的。类型A
无法隐式转换为类型B
。就编译器而言,您正在尝试将DbContext
转换为FormControl
,并且它不知道如何执行此操作。你需要明确告诉它该做什么。一个例子,虽然不是很好:
public DbSet<MyEFDataAccess.Customer> Customer { get; set; }
和
public IQueryable<CustomerViewModel> GetCustomerViewModels()
{
return _context.Customer.Select(
customer => new CustomerViewModel
{
// <assign properties here>
}
);
}
话虽这么说,从你的控制器返回IQueryable<T>
是一个肯定的禁忌。您肯定希望允许使用者查询特定记录。您可以执行此操作以启用分页,例如:
public async Task<List<CustomerViewModel>> GetCustomerViewModels(
int skip = 0,
int take = 100
)
{
return await _context.Customer
.Skip(skip)
.Take(take)
.Select(
customer => new CustomerViewModel
{
// <assign properties here>
}
)
.ToListAsync();
}