• 是否需要手动执行DataContext的Dispose方法?


    我们知道DataContext实现了IDisposable接口。在C#中,凡是实现了IDisposable接口的类,都推荐的使用using语句。如下:

    using (DataContext db = new DataContext(fileOrServerOrConnection))
    { 
        //...
    }

    使用using语句可以确保以正确的方式调用Dispose方法,即使在语句块中出现异常,Dispose方法也将被执行。

    但当我们使用如下代码时,将不可避免地得到“System.ObjectDisposedException: 无法访问已释放的对象”异常:

    static void Main()
    {
        var products = GetProductByPrice(20);
        foreach (var p in products)
        { 
            // ...
        }
    }
    
    private static IEnumerable<Product> GetProductsByPrice(decimal price)
    {
        using (NorthwindDataContextDataContext db = new NorthwindDataContextDataContext())
        {
            var product = from p in db.Products
                          where p.UnitPrice >= price
                          select p;
            return product;
        }
    }

    由于延迟加载的特性,LINQ to SQL其实并没有真正查询数据库,而会将实际查询放到遍历时才进行(在Table.GetEnumerator方法内部调用SqlProvider的Execute方法)。而此时DataContext早已Dispose,自然无法访问。

    解决此问题有两种方法:

    1. GetProductsByPrice方法返回时执行ToList方法,这将立即执行查询。
    2. 不手动Dispose。这样将会在遍历的时候执行查询。

    使用方法1等于摒弃了延迟查询的优势,而使用方法2,是否会对系统造成过多的负载呢?

    对此,我翻阅了一些资料,发现尽管有的支持手动Dispose的方式,但更多的则认为没有必要这么做:

    我们用Reflector打开DataContext,可以看到在其Dispose方法中调用了SqlProvider的Dispose方法。而SqlProvider.Dispose方法主要任务是关闭数据库连接(调用SqlConnectionManager.DisposeConnection方法,再跟下去可以发现实际上最终是调用了SqlConnection.Close方法),剩下的无论是在DataContext还是SqlProvider的Dispose方法中,都只是将一些对象置为null。

    而DataContext其实已经将数据连接的打开和关闭管理得井井有条了。在DataContext.SubmitChanges方法中可以看到,在finally块中调用了SqlConnection.Close方法。而负责执行查询的DataContext.ExecuteQuery方法跟踪到最后也会在SqlProvider.Execute方法的finally块中调用SqlConnectionManager的ReleaseConnection方法。也就是说在我们手动Dispose DataContext的时候,其实主要工作早已经执行完了,剩下的只是清空一些对象所占用的内存,使它们尽早被GC回收。除此之外,DataContext.Dispose再没有其他好处了。并且我们会发现SqlConnectionManager的ReleaseConnection方法所执行的内容甚至比CloseConnection还要多。

    因此我们得出结论,在使用LINQ to SQL时,完全没有必要手动执行DataContext的Dispose方法,更没有必要使用using语句。

    但是我们不禁会问,既然DataContext实现了IDisposable接口,那么为什么还要在ExecuteQuery和SubmitChanges等方法中执行资源释放的操作呢?这是否是一个设计方面的缺陷呢?欢迎您的讨论。

  • 相关阅读:
    java学习
    瓜娃《guava》api快速入门
    List,set,Map 的用法和区别
    css selector
    字节流与字符流区别
    jsoup的elements类
    javaio-printwriter
    map遍历的四种方法
    kafka集群和zookeeper集群的部署,kafka的java代码示例
    Ubuntu12.04安装中文字体(转)
  • 原文地址:https://www.cnblogs.com/techfans/p/4111001.html
Copyright © 2020-2023  润新知