创建通过存储库执行数据库调用的服务的正确方法是什么?
我正在开发一项服务,该服务通过存储库执行数据库操作。在服务中,我实例化了存储库,该存储库需要构造函数中的数据库上下文。我想知道上下文是否应该传递到服务中,或者下面的代码是否正确。或者将 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();
}
}
I am working on a service, which performs database operations through a repository. In the service I instantiate the repository which requires a database context in the constructor. I wanted to know if the context should be passed into the Service, or if the code below is fine. Or would it be better to pass a Repository object to the service for it to use? What should the UI code look like when using the Service class?
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();
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
事实上,最好通过 Service 的构造函数将存储库传递给 Service,如下所示:
通常,表示 UI 的类将依赖于 Service,因此代码可能如下所示:
接下来您需要做的是配置一个控制反转容器,它将知道如何解析 IRepository 实例(并在需要时向它们提供适当的 DataContext 实例)。
例如,如果我们的 UI 代码是 MVC3 控制器,我们会告诉容器解析该控制器的实例。发生的情况如下:
容器注意到对
Service
的依赖(在构造函数中)并尝试解决它。由于
Service
是一个具体类,容器将尝试解析它,然后请注意对
IRepository
的依赖。由于这是一个接口,因此
IRepository
的解析要求容器事先已设置为“知道”当请求其实例时要返回什么。通常,这只是接口与其具体实现之间的映射。在我们的例子中,具体实现是Repository
并且容器还负责“知道”如何实例化它所需的DataContext
实例(这也必须是由于有了存储库实例,容器就能够首先正确实例化
Service
,然后是控制器类。请注意,具体类的自动解析并不是所有 IoC 容器都具备的功能;有些需要显式配置才能执行此操作。
除此之外,我认为
Service
类在您的情况下不会增加太多价值。它仅包含对存储库实现的方法的委托。在这种情况下,最好让 UI 直接依赖于IRepository
并简单地删除Service
类。但是,如果这个
Service
类只是一个示例,并且在您的实际项目中它实现了实际的业务规则,那么应该保留它。更新:如何解决 ASP.Net Webforms 中的依赖关系
我上面提供的示例是理想的依赖注入场景。例如,它可以在 ASP.NET MVC 中工作,其中 BaseClassDictatedByCurrentUIFramework 将为
Controller
- 在这种情况下,框架允许我们控制实例化控制器的组件,因此我们可以在构造函数中注入我们自己的依赖项。然而,ASP.Net WebForms 并不是一个对 DI 非常友好的框架。它要求每个
Page
都需要有一个默认构造函数,这使得所有构造函数注入的思想都不适合。在这种情况下,一种可能的解决方案是以下折衷方案:
Page
private readonly
字段,但构造函数在构造函数体内 :请注意,这种方法需要纪律 - 很容易在构造函数之外的其他地方使用容器来解决其他组件。这种方法称为服务定位器,它被认为是一种反模式 (http://blog.ploeh .dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx),因此应避免使用。
Indeed, it would be better to pass a repository to the Service via the Service's constructor, like so:
Tipically, the class representing the UI would take a dependency on Service, so the code might look like this:
What you have to do next is configure an Inversion of Control container that will know how to resolve instances of IRepository (and feeding them appropriate DataContext instance, if needed).
For example, if our UI code would be an MVC3 controller, we'd tell the container to resolve an instance of this controller. This is what happens:
The container notices the dependency on
Service
(in the constructor) and tries to resolve it.Since
Service
is a concrete class, the container will attempt to resolve it and thennotice the dependency on
IRepository<WWW>
.The resolution of
IRepository
, since this is an interface, requires that the container has been previously set up to "know" what to return when it's asked for an instance of it. Normally, this is just a mapping between the interface and a concrete implementation of it. In our case the concrete implementation isRepository<WWW>
and the container is also responsible for "knowing" how to instantiate the neededDataContext
instance for it (this also has to be previously configured)Having a repository instance, the container is then able to properly instantiate first the
Service
, then the controller class.Note that the automatic resolution of concrete classes is a feature not all IoC containers have; some require explicit configuration in order to do so.
Apart from this, I think the
Service
class does not add much value in your case. It only contains delegations to methods implemented by the repository. In this case it could be better to have the UI take a dependency on theIRepository<WWW>
directly and simply delete theService
class.However, if this
Service
class was just an example and in your real project it implements actual business rules, then it should be kept.Update: How to resolve dependencies in ASP.Net Webforms
The example I presented above is the ideal Dependency Injection scenario. It would work for example in ASP.NET MVC, where BaseClassDictatedByCurrentUIFramework would be
Controller
- in that case the framework allows us to control the components that instantiate Controllers, so we can inject our own dependencies in the constructor.However, ASP.Net WebForms is not a very DI-friendly framework. It requires that every
Page
is required to have a default constructor, which makes all the constructor injection idea not suitable.In this case one possible solution would be the following compromise:
Page
class declare dependencies asprivate readonly
fields, but the constructor will not have corresponding parameters (it will have no parameters at all)Please note that this approach requires discipline - it is easy to use the container somewhere else that the constructor to resolve other components. This approach is called Service Locator, it's considered an antipattern (http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx) and should therefore be avoided.
我建议加大依赖倒置。就我个人而言,我认为这不是您是否应该向服务传递 DBContext 的问题,而是您应该向服务传递 Repository 本身的问题。
I would suggest one-upping the dependency inversion. Personally, I view it not as whether you should pass the service the DBContext or not, but that you should pass the service the Repository itself.