拥有一个手动打开和关闭数据库连接的存储库是不好的做法吗?

时间:2012-02-13 19:28:26

标签: c# asp.net-mvc-3 datacontext object-lifetime

环境:ASP.NET MVC3 C#

说我有一些存储库(半伪装):

public interface IRepository
{
 create();read();update();delete();opendb();closedb();
}

public class CarRepository : IRepository
{
 private DbContext namedDbContext;

 public void opendb()
 {
  namedDbContext = new DbContext();
 }
 public void closedb()
 {
  namedDbContext.dispose();
 }
}

然后在控制器中注入存储库并按如下方式使用以手动控制数据库连接生存期:

public class SomeController : Controller
{
    private IRepository CarRepository;

    public void SomeController(IRepository _carRepository)
    {
        CarRepository = _carRepository;
    }

    public ActionResult SomeAction(int CarId)
    {
        CarRepository.opendb();
        var car = CarRepository.read(CarId);
        CarRepository.closedb();
    }
}

这被认为是不好的做法,因为它是从存储库控制连接并将其放在控制器中?我担心使用依赖注入会导致内存泄漏,并且希望确保不会打开重复的连接,也不会长时间运行和未使用。

3 个答案:

答案 0 :(得分:2)

是。当然。大多数ADO.NET驱动程序都使用连接池,因此实际的连接过程并不那么重。你有TransactionScope可以处理多个连接上的事务,但它不会像一个连接上的一个事务一样快。

  

我担心使用依赖注入会导致内存泄漏,并且希望确保不会打开重复的连接,也不会长时间运行和未使用。

IoC将保证清理连接(大型用户群确保了这一点)。无法保证程序员可以在所有地方进行清理。

答案 1 :(得分:1)

存储库的一部分正在抽象出持久性的细节。

我发现您的提案有两个问题:

  1. 通过命名这些方法“opendb”和“closedb”以及
  2. ,您正在泄露超出必要的抽象范围
  3. 如果你沿着这条路走下去,你应该从IDisposable方法返回opendb()(连接对象),并将动作包装在using块中,以确保连接得到闭合。
  4. 通常,您可以让存储库为每个方法创建一个连接,因此您只需要在存储库方法中正确使用它。当您想对存储库执行多个操作时,就会遇到挑战,而不需要为每个部分使用单独的连接。

    要实现这一点,您可以从存储库中公开工作单元的概念。您的工作单元将实现存储库方法的接口,因此您无法在工作单元之外调用它们。它还将实现IDisposable,因此每当您调用存储库时,您将使用using块。在内部,存储库将管理连接,但既不会暴露连接也不会“谈论它”。

    例如:

    public ActionResult SomeAction(int CarId)
    {
         using (var repo = CarRepository.BeginUnitOfWork())
         {
            var car = repo.read(CarId);
            // do something meaningful with the car, do more with the repo, etc.
         }
    }
    

答案 2 :(得分:1)

REpository模式提供了持久层的抽象。它不应该暴露任何持久性细节,例如db connection。如果存储是xml文件或云存储怎么办?

所以是的,这是不好的做法。如果您想要更多控制,可以使存储库使用工作单元模式,以便更高级别应该决定何时提交事务,但就是这样。存储库不应该公开数据库的知识。

AS内存泄漏,使存储库实现IDIsposable(关闭任何未完成的开放式连接)并确保DI容器按请求管理存储库实例,它将在其上调用Dispose。