我应该在 .Net Core Web API 或服务接口中使用 DbContext 吗?
Should I use a DbContext in my .Net Core Web API or a Service Interface?
我接受了一份工作面试评估,评估要求我在 .Net Core 中制作 Web API。我从来没有在 .Net Core 中从头开始构建 Web API,所以我浏览了很多教程,有一件事让我很困惑。在一些教程中,示例使用服务接口来处理控制器和模型之间的业务逻辑,例如:
[Route("/api/[controller]")]
public class CategoriesController : Controller
{
private readonly ICategoryService _categoryService;
private readonly IMapper _mapper;
public CategoriesController(ICategoryService categoryService, IMapper mapper)
{
_categoryService = categoryService;
_mapper = mapper;
}
[HttpGet]
public async Task<IEnumerable<CategoryResource>> GetAllAsync()
{
var categories = await _categoryService.ListAsync();
var resources = _mapper.Map<IEnumerable<Category>, IEnumerable<CategoryResource>>(categories);
return resources;
}
并且在一些教程中,示例是在控制器中使用 DbContext 来实现模型的 CRUD 操作,通常在添加 Entity Framework 脚手架时自动生成,例如:
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class ProductsController : ControllerBase
{
private readonly InventoryContext _context;
public ProductsController(InventoryContext context)
{
_context = context;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<Products>>> GetProducts()
{
return await _context.Products.ToListAsync();
}
我很困惑 right/better 是哪条路,为什么?这是 Entity Framework 的事吗?是否取决于模型的复杂程度或模型之间的关系?
.Net Core 的文档和示例很多,做更多的研究只会让我陷入困境。如果有人能向我解释我在这里处理的是什么,我将不胜感激。
这取决于您的应用程序架构和结构。如果项目包含多层,那么最好使用第一种方法。
在第一种方法中,使用了依赖注入,它负责创建服务 class 实例到服务接口。它被称为国际奥委会。
第二种方法很简单。如果不使用其他层则直接通过上下文与数据库模型交互获取数据库数据。
有时数据库 table 准确地代表了您服务的用户所期望的。通常,数据库 table 具有您不想导出给服务用户的值。在这些情况下,您希望将数据库类型与您 return 给用户的类型分离。如果人们查询数据,数据库 table 将被翻译成您 return.
的类型
假设您有一个包含学校、教师和学生的数据库。它们在学校与教师之间、学校与学生之间具有明显的一对多关系。 Teacher 和 Student 之间是多对多的关系:每个 Teacher 有零个或多个 Student,每个 Student 都被零个或多个 Teachers 教过。
通常在关系数据库中,一对多关系是使用外键实现的。多对多关系是使用连接 table.
实现的
解耦return仅用户期望的数据
假设您可以查询“Schools with their Students”的服务。另一个查询:“给我老师和他们的学生”。用户对您如何获得结果不感兴趣。他们不想知道您使用外键和联结 tables.
解耦使您能够return不在数据库中的数据
解耦让您可以自由地为您提供数据库中数据以外的其他数据。
“给我 X 市的学校及其学生总数”。学生总数不在学校的任何地方 table。
解耦可以忽略敏感数据
returned 数据和数据库 table 之间的分离使您可以省略某些值。如果人们问“给我 X 老师的学生”,他们不会指望学生所在学校的外键。您也可以省略学生的行为报告。
解耦允许为不同的用户自定义类型
需要为学生查询数据的教师可能需要与想要知道同学地址的学生不同的数据。老师可能需要知道成绩。学生可以看到自己的成绩,但看不到其他学生的成绩。
解耦允许更改数据库
最后,它使您无需更改服务接口即可更改数据库。例如,假设人们抱怨说,如果他们犯了一个错误,并且不小心删除了一个项目,他们将无法再被删除。一种流行的方法是添加一个DateTime?
属性 DeletedDate
。 “删除学生”方法会将日期分配给 DeletedDate
,它不会删除学生。如果操作员犯了错误,那么取消删除将很容易:只需再次将 null 分配给 DeletedDate
即可。一个单独的过程会定期(比如说每月一次)删除 DeletedDate
比一年前早的项目,没有人会想再次取消删除的项目。
结论
将数据库 table 与您 return 的数据分离是一个很好的设计。它是为改变而设计的,它支持可重用性,它更容易让用户理解数据,可以隐藏你的内部结构。后者也使单元测试更容易。
自动映射器或 DbContext?
这不是真正的区别。不同之处在于:您想使用 LINQ 将您获取的数据转换为您使用的格式,还是自动映射器?
恕我直言,使用 LINQ 可以更轻松地查看转换数据时所做的操作。 LINQ 也不使用反射,因此速度更快。
简而言之,您想像第一个示例一样为您的业务逻辑使用服务层。由于其他人已经概述的许多原因,这将使您有更大的控制权。
解耦一开始可能看起来很乏味,但是当项目增长时,它实际上简化了以后进行更改的过程。无论它是 Web api、wcf、gRPC 还是只是 MVC 的常规视图模型,使用单独的 request/response-objects(如果愿意,则为 DTO)几乎总是更好。
当谈到是否使用 Automapper 时,我更喜欢编写扩展或只是手动映射数据我想在重命名任何内容时出现编译时错误。
我接受了一份工作面试评估,评估要求我在 .Net Core 中制作 Web API。我从来没有在 .Net Core 中从头开始构建 Web API,所以我浏览了很多教程,有一件事让我很困惑。在一些教程中,示例使用服务接口来处理控制器和模型之间的业务逻辑,例如:
[Route("/api/[controller]")]
public class CategoriesController : Controller
{
private readonly ICategoryService _categoryService;
private readonly IMapper _mapper;
public CategoriesController(ICategoryService categoryService, IMapper mapper)
{
_categoryService = categoryService;
_mapper = mapper;
}
[HttpGet]
public async Task<IEnumerable<CategoryResource>> GetAllAsync()
{
var categories = await _categoryService.ListAsync();
var resources = _mapper.Map<IEnumerable<Category>, IEnumerable<CategoryResource>>(categories);
return resources;
}
并且在一些教程中,示例是在控制器中使用 DbContext 来实现模型的 CRUD 操作,通常在添加 Entity Framework 脚手架时自动生成,例如:
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class ProductsController : ControllerBase
{
private readonly InventoryContext _context;
public ProductsController(InventoryContext context)
{
_context = context;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<Products>>> GetProducts()
{
return await _context.Products.ToListAsync();
}
我很困惑 right/better 是哪条路,为什么?这是 Entity Framework 的事吗?是否取决于模型的复杂程度或模型之间的关系?
.Net Core 的文档和示例很多,做更多的研究只会让我陷入困境。如果有人能向我解释我在这里处理的是什么,我将不胜感激。
这取决于您的应用程序架构和结构。如果项目包含多层,那么最好使用第一种方法。
在第一种方法中,使用了依赖注入,它负责创建服务 class 实例到服务接口。它被称为国际奥委会。
第二种方法很简单。如果不使用其他层则直接通过上下文与数据库模型交互获取数据库数据。
有时数据库 table 准确地代表了您服务的用户所期望的。通常,数据库 table 具有您不想导出给服务用户的值。在这些情况下,您希望将数据库类型与您 return 给用户的类型分离。如果人们查询数据,数据库 table 将被翻译成您 return.
的类型假设您有一个包含学校、教师和学生的数据库。它们在学校与教师之间、学校与学生之间具有明显的一对多关系。 Teacher 和 Student 之间是多对多的关系:每个 Teacher 有零个或多个 Student,每个 Student 都被零个或多个 Teachers 教过。
通常在关系数据库中,一对多关系是使用外键实现的。多对多关系是使用连接 table.
实现的解耦return仅用户期望的数据
假设您可以查询“Schools with their Students”的服务。另一个查询:“给我老师和他们的学生”。用户对您如何获得结果不感兴趣。他们不想知道您使用外键和联结 tables.
解耦使您能够return不在数据库中的数据
解耦让您可以自由地为您提供数据库中数据以外的其他数据。
“给我 X 市的学校及其学生总数”。学生总数不在学校的任何地方 table。
解耦可以忽略敏感数据
returned 数据和数据库 table 之间的分离使您可以省略某些值。如果人们问“给我 X 老师的学生”,他们不会指望学生所在学校的外键。您也可以省略学生的行为报告。
解耦允许为不同的用户自定义类型
需要为学生查询数据的教师可能需要与想要知道同学地址的学生不同的数据。老师可能需要知道成绩。学生可以看到自己的成绩,但看不到其他学生的成绩。
解耦允许更改数据库
最后,它使您无需更改服务接口即可更改数据库。例如,假设人们抱怨说,如果他们犯了一个错误,并且不小心删除了一个项目,他们将无法再被删除。一种流行的方法是添加一个DateTime?
属性 DeletedDate
。 “删除学生”方法会将日期分配给 DeletedDate
,它不会删除学生。如果操作员犯了错误,那么取消删除将很容易:只需再次将 null 分配给 DeletedDate
即可。一个单独的过程会定期(比如说每月一次)删除 DeletedDate
比一年前早的项目,没有人会想再次取消删除的项目。
结论
将数据库 table 与您 return 的数据分离是一个很好的设计。它是为改变而设计的,它支持可重用性,它更容易让用户理解数据,可以隐藏你的内部结构。后者也使单元测试更容易。
自动映射器或 DbContext?
这不是真正的区别。不同之处在于:您想使用 LINQ 将您获取的数据转换为您使用的格式,还是自动映射器?
恕我直言,使用 LINQ 可以更轻松地查看转换数据时所做的操作。 LINQ 也不使用反射,因此速度更快。
简而言之,您想像第一个示例一样为您的业务逻辑使用服务层。由于其他人已经概述的许多原因,这将使您有更大的控制权。
解耦一开始可能看起来很乏味,但是当项目增长时,它实际上简化了以后进行更改的过程。无论它是 Web api、wcf、gRPC 还是只是 MVC 的常规视图模型,使用单独的 request/response-objects(如果愿意,则为 DTO)几乎总是更好。
当谈到是否使用 Automapper 时,我更喜欢编写扩展或只是手动映射数据我想在重命名任何内容时出现编译时错误。