2010-04-21 61 views
5

我将我的linq封装到在我的重载控制器的构造函数中实例化的存储库类中的sql调用。我的存储库类的构造函数创建数据上下文,以便在页面加载的整个过程中只使用一个数据上下文。即使我明确处理DataContext,为什么我的连接没有关闭?

在我的存储库类的析构函数中,我显式调用了DataContext的处理,尽管我不认为这是必要的。

使用性能监视器时,如果我看我的用户连接数并重复加载页面,则每页加载次数会增加一次。连接不会关闭或重用(约20分钟)。

我试着把Pooling = false放在我的配置中,看看这是否有效果,但没有。在任何情况下,我都不希望每个负载都有一个新的连接,我希望它能够重用连接。

我试着在析构函数中放置一个断点,以确保处置正在被击中,并且确实已经足够了。那么发生了什么?

一些代码来说明我上面说:

控制器:

public class MyController : Controller 
{ 
    protected MyRepository rep; 

    public MyController() 
    { 
     rep = new MyRepository(); 
    } 
} 

存储库:

public class MyRepository 
{ 
    protected MyDataContext dc; 

    public MyRepository() 
    { 
     dc = getDC(); 
    } 

    ~MyRepository() 
    { 
     if (dc != null) 
     { 
      //if (dc.Connection.State != System.Data.ConnectionState.Closed) 
      //{ 
      // dc.Connection.Close(); 
      //} 
      dc.Dispose(); 
     } 
    } 

    // etc 
} 

注:我添加了一些提示和上下文信息的DC用于审计目的。这基本上就是为什么我想每个页面加载一个连接

更新: 已经实现了IDisposable在我的仓库,并在我的控制器类我无法找到一个方法来专门调用Dispose方法我的控制器作为后上控制器由MvcHandler在幕后创建和销毁。不过,我确实发现我的联系无论如何都被关闭了。我不舒服知道这是工作,但不知道为什么,所以我做了一些挖掘,发现了一个MSDN的报价,让我开心:

当执行完成后,将MvcHandler如果控制器实现IDisposable检查界面,如果是的话,将调用控制器上的Dispose来清理非托管资源。

最后更新: 一个月左右的时间与工作这个现在我已经删除了所有这些代码,并走了下来MS劝我在公共仓库方法缠绕在代码中的“使用”声明的路线后并将这个DC传递给私有方法。这看起来有点浪费和重复,并导致更多的连接被打开和关闭。但我得到的LINQ到SQL缓存,我只能通过重置DC来解决。

回答

4

正确的模式(简短但足够的版本)在这里是:

public class MyRepository : IDisposable 
{ 
    ... // everything except the dtor 

    public void Dispose() 
    { 
     if (dc != null) 
     { 
      dc.Dispose(); 
     } 
    } 
} 

public class MyController : Controller, IDisposable 
{ 
    protected MyRepository rep; 

    public MyController() 
    { 
     rep = new MyRepository(); 
    } 

    public void Dispose() 
    { 
     if (rep!= null) 
     { 
      rep.Dispose(); 
     } 
    } 
} 

现在你可以(应该)使用与myController的所使用的子句:

using (var ctl = new MyController()) 
{ 
    // use ctl 
} 

编辑:
只注意到它级联到myController的,代码添加。这显示了非托管资源的间接所有权如何分散。

编辑2:
这也是正确的(如将是一个try /终于):

var ctl = GetController(); 
using (ctl) 
{ 
    // use ctl 
} 

如果你不能保持它的地方到1点的方法,只是做你最好打电话CTL .Dispose()在关闭事件或类似事件中。

+0

啊,谢谢。我只是想知道我的代码是否需要添加(指编辑) – 2010-04-21 20:22:18

+0

我不太确定最后一点。 MVC生成我的控制器,那么我该如何确保它被正确处理? – 2010-04-21 20:26:56

+0

@Chris,继承时要小心,我注意到你使这些字段受到保护。我不会有。 – 2010-04-21 20:31:02

2

析构函数只能由GC调用。你的MyRepository应该实现Dispose模式,并在那里处置dc。

看到这个问题的更多细节。 In C# what is the difference between a destructor and a Finalize method in a class?

MyRepository应该实现IDisposable,任何可丢弃的对象都应该放在那里,如果你在对象的生命周期中持有它们。

很多时候你使用的是一次性的对象的时候,你应该把它包在使用块

using(var dc = getDC()) 
{ 
    //do stuff with the dc 
}//the dc will be Disposed here 

编辑:链接到语言指南C#析构函数 http://msdn.microsoft.com/en-us/library/66x5fx1b(v=VS.100).aspx

+0

而__not__实现析构函数。它在这堂课没有任何用处。 – 2010-04-21 20:05:09

+0

啊,你是说Dispose不应该在析构函数中调用吗? – 2010-04-21 20:05:43

+0

约定的析构函数应该在c#应用程序中很少使用。 – 2010-04-21 20:08:18

0

我同意这样的事实,一次性碎片是不正确的,Henk HoltermanDarryl Braaten以上的建议是非常好的,我不认为它回答您的根本问题。

您的问题的答案是调用Dispose MyRepository(假设它的DataContext)不会关闭连接。它只是将连接返回到池以备下次使用。

This SO Post,说明了当你应该担心关闭连接...

+0

原来的问题已经解决了池化问题(“连接没有关闭或重新使用...”) – 2010-04-21 20:59:17

+0

请问您可以重新说明一下吗?我不跟? – Nix 2010-04-21 21:05:15

+0

它看起来不像连接正在返回到池中。无论是打开还是关闭池总是会创建新的连接,而不是重新使用 – 2010-04-21 21:29:17

相关问题