在 LINQ-SQL 中,将 DataContext 包装为一个 using 语句 - 优点 缺点

发布于 2024-08-22 06:35:20 字数 742 浏览 7 评论 0原文

有人可以从性能、内存使用、编码简易性、正确做法等因素方面阐述将 DataContext 包装在 using 语句中或不在 LINQ-SQL 中之间的优缺点吗?

更新:在一个特定的应用程序中,我经历过,如果没有将 DataContext 包装在 using 块中,内存使用量会不断增加,因为活动对象没有被释放以进行 GC。如下例所示,如果我持有对 q 对象列表的引用并访问 q 的实体,我将创建一个不为 GC 释放的对象图。

DataContext 使用

    using (DBDataContext db = new DBDataContext())
    {
        var q = 
            from x in db.Tables
            where x.Id == someId
            select x;

        return q.toList();
    }

DataContext 而不使用 using 并保持活动状态,

  DBDataContext db = new DBDataContext()
  var q = 
        from x in db.Tables
        where x.Id == someId
        select x;

    return q.toList(); 

谢谢。

Can someone pitch in their opinion about pros/cons between wrapping the DataContext in an using statement or not in LINQ-SQL in terms of factors as performance, memory usage, ease of coding, right thing to do etc.

Update: In one particular application, I experienced that, without wrapping the DataContext in using block, the amount of memory usage kept on increasing as the live objects were not released for GC. As in, in below example, if I hold the reference to List of q object and access entities of q, I create an object graph that is not released for GC.

DataContext with using

    using (DBDataContext db = new DBDataContext())
    {
        var q = 
            from x in db.Tables
            where x.Id == someId
            select x;

        return q.toList();
    }

DataContext without using and kept alive

  DBDataContext db = new DBDataContext()
  var q = 
        from x in db.Tables
        where x.Id == someId
        select x;

    return q.toList(); 

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

荒岛晴空 2024-08-29 06:35:20

相对于其他事物,DataContext 的创建成本可能很高。但是,如果您完成了它并希望尽快关闭连接,这将做到这一点,并从上下文中释放所有缓存的结果。请记住,无论如何,您都会创建它,在这种情况下,您只是让垃圾收集器知道还有更多免费的东西可以删除。

DataContext 被设计为一个简短的 use 对象,使用它,完成工作单元,然后退出......这正是您使用 using 所做的事情。

所以优点:

  • 更快的关闭连接
  • 从处置中释放内存(内容中的缓存对象)

缺点 - 更多代码?但这不应该成为一种威慑,您在这里正确地使用了 using

看看微软的答案: http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/2625b105-2cff-45ad-ba29-abdd763f74fe

如果您需要使用 using/.Dispose():

简短的回答;不,您不必这样做,但您应该...

A DataContext can be expensive to create, relative to other things. However if you're done with it and want connections closed ASAP, this will do that, releasing any cached results from the context as well. Remember you're creating it no matter what, in this case you're just letting the garbage collector know there's more free stuff to get rid of.

DataContext is made to be a short use object, use it, get the unit of work done, get out...that's precisely what you're doing with a using.

So the advantages:

  • Quicker closed connections
  • Free memory from the dispose (Cached objects in the content)

Downside - more code? But that shouldn't be a deterrent, you're using using properly here.

Look here at the Microsoft answer: http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/2625b105-2cff-45ad-ba29-abdd763f74fe

Short version of if you need to use using/.Dispose():

The short answer; no, you don't have to, but you should...

偏爱自由 2024-08-29 06:35:20

嗯,这是一个 IDisposable,所以我想这不是一个坏主意。 MSFT 的人员表示,他们使 DataContext 尽可能轻量级,以便您可以不计后果地创建它们,因此您可能不会获得太多好处......

Well, It's an IDisposable, so I guess it's not a bad idea. The folks at MSFT have said that they made DataContexts as lightweight as possible so that you may create them with reckless abandon, so you're probably not gaining much though.....

蝶舞 2024-08-29 06:35:20
  1. 第一次 DataContext 将从 DB 获取对象。
  2. 下次您触发查询以获取相同的对象(相同的参数)时。:您将在分析器中看到查询,但 DataContext 中的对象不会被数据库中的新对象替换!

更不用说每个 DataContext 背后都是您从数据库请求的所有对象的身份映射(您不想保留它)。

DataContext 的整个理念是工作单元乐观并发
将其用于短期交易(仅提交一次)并处置。

不要忘记 dispose 的最好方法是使用 ()。

  1. First time DataContext will get object from DB.
  2. Next time you fire a query to get the same object (same parameters).: You’ll see query in a profiler but your object in DataContext will not be replaced with new one from DB !!

Not to mention that behind every DataContext is identity map of all objects you are asking from DB (you don’t want to keep this around).

Entire idea of DataContext is Unit Of Work with Optimistic Concurrency.
Use it for short transaction (one submit only) and dispose.

Best way to not forget dispose is using ().

枫林﹌晚霞¤ 2024-08-29 06:35:20

我取决于你的数据层的复杂性。如果每个调用都是一个简单的单个查询,那么每个调用都可以像您的问题中那样包装在“使用”中,这样​​就可以了。

另一方面,如果您的数据层可以预期来自业务层的多个连续调用,那么您最终会为每个较大的调用序列重复创建/处置 DataContext。不理想。

我所做的是将数据层对象创建为 IDisposible。创建时,会创建 DataContext(或者实际上是在第一次调用方法后),并且当数据层对象释放时,它会关闭并释放 DataContext。

它看起来像这样:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;

namespace PersonnelDL
{
    public class PersonnelData : IDisposable
    {
        #region DataContext management
        /// <summary>
        /// Create common datacontext for all data routines to the DB
        /// </summary>
        private PersonnelDBDataContext _data = null;
        private PersonnelDBDataContext Data
        {
            get
            {
                if (_data == null)
                {
                    _data = new PersonnelDBDataContext(ConfigurationManager.ConnectionStrings["PersonnelDB"].ToString());
                    _data.DeferredLoadingEnabled = false; // no lazy loading
                    //var dlo = new DataLoadOptions(); // dataload options go here
                }
                return _data;
            }
        }

        /// <summary>
        /// close out data context
        /// </summary>
        public void Dispose()
        {
            if (_data != null)
                _data.Dispose();
        }
        #endregion

        #region DL methods
        public Person GetPersonByID(string userid)
        {
            return Data.Persons.FirstOrDefault(p => p.UserID.ToUpper().Equals(userid.ToUpper()));
        }

        public List<Person> GetPersonsByIDlist(List<string> useridlist)
        {
            var ulist = useridlist.Select(u => u.ToUpper().Trim()).ToList();
            return Data.Persons.Where(p => ulist.Contains(p.UserID.ToUpper())).ToList();
        }

        // more methods...
        #endregion
    }
}

I depends on the complexity of your Data Layer. If every call is a simple single query, then each call can be wrapped in the Using like in your question and that would be fine.

If, on the other hand, your Data Layer can expect multiple sequential calls from the Business Layer, the you'd wind up repeatedly creating/disposing the DataContext for each larger sequence of calls. not ideal.

What I've done is to create my Data Layer object as IDisposible. When it's created, the DataContext is created (or really, once the first call to a method is made), and when the Data Layer object disposes, it closes and disposes the DataContext.

here's what it looks like:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;

namespace PersonnelDL
{
    public class PersonnelData : IDisposable
    {
        #region DataContext management
        /// <summary>
        /// Create common datacontext for all data routines to the DB
        /// </summary>
        private PersonnelDBDataContext _data = null;
        private PersonnelDBDataContext Data
        {
            get
            {
                if (_data == null)
                {
                    _data = new PersonnelDBDataContext(ConfigurationManager.ConnectionStrings["PersonnelDB"].ToString());
                    _data.DeferredLoadingEnabled = false; // no lazy loading
                    //var dlo = new DataLoadOptions(); // dataload options go here
                }
                return _data;
            }
        }

        /// <summary>
        /// close out data context
        /// </summary>
        public void Dispose()
        {
            if (_data != null)
                _data.Dispose();
        }
        #endregion

        #region DL methods
        public Person GetPersonByID(string userid)
        {
            return Data.Persons.FirstOrDefault(p => p.UserID.ToUpper().Equals(userid.ToUpper()));
        }

        public List<Person> GetPersonsByIDlist(List<string> useridlist)
        {
            var ulist = useridlist.Select(u => u.ToUpper().Trim()).ToList();
            return Data.Persons.Where(p => ulist.Contains(p.UserID.ToUpper())).ToList();
        }

        // more methods...
        #endregion
    }
}
疾风者 2024-08-29 06:35:20

在一个特定的应用程序中,我发现,如果没有将 DataContext 包装在 using 块中,内存使用量就会持续增加,因为活动对象没有被释放以进行 GC。如下例所示,如果我保存对 List 对象的引用并访问 q 的实体,我将创建一个不会为 GC 释放的对象图。

DBDataContext db = new DBDataContext()
var qs = 
    from x in db.Tables
    where x.Id == someId
    select x;

return qs.toList();

foreach(q in qs)
{
    process(q);
    // cannot dispose datacontext here as the 2nd iteration 
    // will throw datacontext already disposed exception 
    // while accessing the entity of q in process() function
    //db.Dispose();
}

process(Table q)
{
    // access entity of q which uses deferred execution
    // if datacontext is already disposed, then datacontext 
    // already disposed exception is thrown
}

在这个示例中,我无法处置数据上下文,因为列表变量 qs 中的所有 Table 实例 **共享相同的数据上下文。在 Dispose() 之后,访问 process(Table q) 中的实体会抛出 datacontext 已处置异常。

对我来说,丑陋的克鲁格是在 foreach 循环之后删除 q 对象的所有实体引用。更好的方法当然是使用 using 语句。

就我的经验而言,我会说使用 using 语句。

In one particular application, I experienced that, without wrapping the DataContext in using block, the amount of memory usage kept on increasing as the live objects were not released for GC. As in, in below example, if I hold the reference to List<Table> object and access entities of q, I create an object graph that is not released for GC.

DBDataContext db = new DBDataContext()
var qs = 
    from x in db.Tables
    where x.Id == someId
    select x;

return qs.toList();

foreach(q in qs)
{
    process(q);
    // cannot dispose datacontext here as the 2nd iteration 
    // will throw datacontext already disposed exception 
    // while accessing the entity of q in process() function
    //db.Dispose();
}

process(Table q)
{
    // access entity of q which uses deferred execution
    // if datacontext is already disposed, then datacontext 
    // already disposed exception is thrown
}

Given this example, I cannot dispose the datacontext because all the Table instances in list variable qs **share the same datacontext. After Dispose(), accessing the entity in process(Table q) throws a datacontext already disposed exception.

The ugly kluge, for me, was to remove all the entity references for q objects after the foreach loop. The better way is to of course use the using statement.

As far as my experience goes, I would say use the using statement.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文