创建通过存储库执行数据库调用的服务的正确方法是什么

本文关键字:服务 是什么 方法 调用 数据库 存储 执行数 执行 创建 | 更新日期: 2023-09-27 18:20:20

我正在开发一项服务,该服务通过存储库执行数据库操作。在服务中,我实例化了存储库,该存储库需要构造函数中的数据库上下文。我想知道上下文是否应该传递到服务中,或者下面的代码是否正确。还是将Repository对象传递给服务以供其使用更好?使用Service类时,UI代码应该是什么样子?

public class Service
    {
        private IRepository<WWW> _repository;
        public Service()
        {
            _repository = new Repository<WWW>(new DBContext());
        }
        public WWW GetWWW(int wwwID)
        {
            return _repository.Get(x => x.WWWID == wwwID).FirstOrDefault();
        }
        public void AddWWW(WWW www)
        {
            _repository.Add(www);
        }
        public void DeleteWWWByID(int wwwID)
        {
            _repository.Delete(x => x.WWWID == wwwID);
        }
        public void SaveChanges()
        {
            _repository.SaveChanges();
        }
    }

创建通过存储库执行数据库调用的服务的正确方法是什么

实际上,最好通过服务的构造函数将存储库传递给服务,如下所示:

public class Service
{
    private readonly IRepository<WWW> _repository;
    public Service(IRepository<WWW> repository)
    {
        _repository = repository;
    }
    /* the rest is unchanged */
}

奇怪的是,表示UI的类将依赖于Service,因此代码可能看起来像这样:

public class UIClass : BaseClassDictatedByCurrentUIFramework
{
    private readonly Service _service;
    public UIClass(Service service)
    {
        _service = service;
    }
    /* UI code that will eventually call methods on the service */
}

接下来要做的是配置一个控制反转容器,该容器将知道如何解析IRepository的实例(并在需要时为它们提供适当的DataContext实例)。

例如,如果我们的UI代码是一个MVC3控制器,我们会告诉容器解析这个控制器的一个实例。这就是发生的事情:

  • 容器注意到对Service(在构造函数中)的依赖,并尝试解决它

  • 由于Service是一个具体类,容器将尝试解析它,然后注意对CCD_ 3的依赖性。

  • 由于IRepository是一个接口,因此它的解析要求容器之前已经设置好,以便在请求它的实例时"知道"返回什么。通常,这只是接口和它的具体实现之间的映射。在我们的案例中,具体实现是Repository<WWW>,容器还负责"知道"如何为其实例化所需的DataContext实例(这也必须事先配置)

  • 有了存储库实例,容器就能够正确地首先实例化Service,然后实例化控制器类。

请注意,具体类的自动解析是并非所有IoC容器都具有的功能;有些需要显式配置才能做到这一点。

除此之外,我认为Service类在您的情况下不会增加太多价值。它只包含对存储库实现的方法的委派。在这种情况下,最好让UI直接依赖于IRepository<WWW>,并简单地删除Service类。但是,如果这个Service类只是一个示例,并且在您的实际项目中它实现了实际的业务规则,那么应该保留它。

更新:如何解决ASP.Net Webforms中的依赖关系

我上面给出的例子是理想的依赖注入场景。例如,它可以在ASP.NET MVC中工作,其中BaseClassDicatedByCurrentUIFramework将为Controller——在这种情况下,框架允许我们控制实例化控制器的组件,因此我们可以在构造函数中注入自己的依赖项。

然而,ASP.Net WebForms并不是一个对DI非常友好的框架。它要求每个Page都有一个默认的构造函数,这使得所有的构造函数注入思想都不合适。

在这种情况下,一种可能的解决方案是以下折衷方案:

  • 在应用程序启动时实例化IoC容器(在Globals.asax中),并通过某些全局状态(例如,应用程序上下文)使其可用
  • Page类中,将依赖项声明为private readonly字段,但构造函数将没有相应的参数(它将根本没有参数)
  • 在构造函数主体中:
    • 获取对IoC容器的引用(可从全局状态获得)
    • 使用容器解析类的所有依赖项

请注意,这种方法需要规程-很容易在构造函数解析其他组件的其他地方使用容器。这种方法被称为服务定位器,它被认为是一种反模式(http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx)因此应予以避免

我建议增加依赖反转。就我个人而言,我并不认为是否应该将DBContext传递给服务,而是应该将Repository本身传递给服务。