我有以下ADO .Net存储库
public class Repository : IRepository,IDisposable { private readonly IUnitOfWork UnitOfWork; private sqlConnection Connection; public Repository(IUnitOfWork unitOfWork,connectionString) { UnitOfWork = unitOfWork; Connection = new sqlConnection(connectionString); Connection.Open(); } public MyObject FindBy(string userName) { //...Ado .Net command.ExecuteReader,etc. } }
此存储库向IOS容器注入域服务,使用方式如下:
public class UserDomainService : IUserDomainService { private readonly IRepository Repository; public UserDomainService(IRepository repository) { Repository = repository; } public User CreateNewUser(User user) { using(Repository) { var user = Repository.FindBy(user.UserName); if(user != null) throw new Exception("User name already exists!"); Repository.Add(user); Repository.Commit(); } } }
我的想法是我总是将Repository对象放在using语句中,所以当它完成时,连接被关闭并被处理掉,但是我认为它是一个问题,因为Domain Service类仍然存在并且如果有第二次调用它,它将失败,因为存储库已被销毁.
现在我可以完全控制所有代码,我只想设计粗粒度服务调用,但有一些东西感觉不对.
我是这样做的,所以我可以避免域服务知道存储库中的OpenConnection和CloseConnection方法.
这种设计本质上是不好的还是有更好的方法来做到这一点?
经过深思熟虑:当请求到达时,所有依赖树都是在WCF级别生成的,当然你可以看到连接是在那个时刻打开的,因为它发生在存储库的构造函数中,所以我相信它不是那么糟糕,因为它仅在此特定呼叫期间开放.我是正确的这个假设还是我在这个过程的早期打开数据库连接做了一件非常糟糕的事情?
解决方法
注入一个工厂,创建您需要的实例,而不是实例本身.
获取IRepositoryFactory,以便您可以创建IRepository并在每次使用时处置它.这样,域服务或工厂都不需要是一次性的.此外,重要的是,通过仍然注入实现而不是硬编码来保持代码抽象.
public class UserDomainService : IUserDomainService { private readonly IRepositoryFactory RepositoryFactory; public UserDomainService(IRepositoryFactory factory) { RepositoryFactory = factory; } public User CreateNewUser(User user) { using (IRepository repository = RepositoryFactory.Create()) { var user = repository.FindBy(user.UserName); if(user != null) throw new Exception("User name already exists!"); repository.Add(user); repository.Commit(); } } }
您并不总是需要注入所需的类型.阅读Castle Windsor(其心态是注册 – 解析 – 释放),您会发现如果您想在应用程序生命周期的不确定时间解析内容,建议使用Type Factories.
你知道你需要一个存储库,但不知道什么时候.而不是要求存储库,请求创建它们的东西.因此保持了抽象级别,并且您没有泄露任何实现.