创建通过存储库执行数据库调用的服务的正确方法是什么
本文关键字:服务 是什么 方法 调用 数据库 存储 执行数 执行 创建 | 更新日期: 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本身传递给服务。