【问题标题】:Entity Framework Core, Unit of Work and Repository Pattern实体框架核心、工作单元和存储库模式
【发布时间】:2019-11-20 18:59:36
【问题描述】:

阅读了许多文章,指出不建议将 UOW 和存储库模式放在 EF Core db 上下文之上,我几乎同意并即将在我的一个新项目中实施注入 IDBContext 的服务。

我说差不多了,因为我以前使用过一个功能,但我不明白如何在没有存储库的情况下实现。

在之前的项目中,我在 EF 之上使用了 UOW 和存储库模式,并从服务访问它们。以下方法将位于存储库中,此后可以通过从任何服务调用 uow.StudentRepository.Get(id) 来调用。

public async Task<Student> Get(Guid id)
    {
        return await _context.Students
            .Include(x => x.Course)
            .Include(x=>x.Address)
            .Include(x => x.Grade)
            .FirstOrDefaultAsync(x => x.Id == id);
    }

如果没有存储库,从 IDBContext 查询,我将不得不调用...

_context.Students
            .Include(x => x.Course)
            .Include(x=>x.Address)
            .Include(x => x.Grade)
            .FirstOrDefaultAsync(x => x.Id == id);

...每次我想做这个查询。这似乎是错误的,因为它不会是干燥的。

问题

有人可以建议一种方法,我可以在没有存储库的情况下在一个地方声明此代码吗?

【问题讨论】:

    标签: entity-framework-core repository unit-of-work


    【解决方案1】:

    听起来您需要一项服务。你可以创建一个像 DbContext 这样的服务,这样你就可以将它注入到你的控制器中。

    IStudentService.cs:

    public interface IStudentService
    {
        Task<List<Student>> GetStudents();
        // Other students methods here..
    }
    

    StudentService.cs

    public class StudentService : IStudentService
    {
        private readonly DataContext _context;
    
        public StudentService(DataContext context)
        {
            _context = context;
        }
    
        public async Task<List<Student>> GetStudents()
        {
            return await _context.Students
            .Include(x => x.Course)
            .Include(x=>x.Address)
            .Include(x => x.Grade)
            .ToListAsync();
        }
    }
    

    然后将服务注册到ConfigureServices() in Startup.cs

    services.AddScoped<IStudentService, StudentService>();
    

    现在您可以将服务注入任何控制器。示例:

    [ApiController]
    [Route("api/[controller]")]
    public class StudentController: ControllerBase
    {
        private readonly IStudentService _studentService;
        private readonly DataContext _context;
    
        public StudentService(DataContext context, IStudentService studentService)
        {
            _context = context;
            _studentService = studentService;
        }
    
        [HttpGet]
        public virtual async Task<IActionResult> List()
        {
            return Ok(await _studentService.GetStudents());
        }
    }
    

    确保仅当您将在多个控制器上使用该服务并避免陷入反模式时才创建该服务。

    【讨论】:

    • 感谢您回复吉列尔莫。我有一个后续问题 - 目前 GetStudents() 在 StudentsRepository 中,可以从工作单元 (uow.Students.GetStudents) 访问。如果我需要从另一个服务访问 GetStudents,我可以从工作单元轻松完成。如果将其移至 StudentService 并且我想从另一个服务(例如 AdminService)访问 GetStudents,将 StudentService 注入 AdminService 是否可以接受?
    • 是的,你可以将StudentService注入到其他服务中,你可以在这里找到更多关于依赖注入的信息:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.0
    • 抱歉进一步的问题,我对 DI 很好,但我不确定这是否是一种合理的架构方式,因为我想避免“混乱”的服务构造函数,即 public PersonService(ILogService logService, ICourseService courseService, IAddressService addressService) 之前我能够从一个工作单元访问所有这些(作为存储库)。
    • 我喜欢这个解决方案,因为您的学生服务本质上是一个隔离的 DAO 类。过去是 UOW 存储库模式的粉丝,我认为这是一个很好的前进方向。
    • 上述提议的服务与存储库有何不同?这里的主要区别似乎只是名义上的。这可能只是一个糟糕的例子,但上面的内容看起来与我遇到的大多数存储库类相同。 Service 通常包含业务逻辑,但在上面它更像是一个“传递”接口(这不一定是好事)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-02
    • 1970-01-01
    • 1970-01-01
    • 2018-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多