В LINQ-SQL обертка DataContext является оператором использования - плюсы и минусы - PullRequest
22 голосов
/ 19 февраля 2010

Может ли кто-то высказать свое мнение о плюсах / минусах между переносом DataContext в оператор использования или нет в LINQ-SQL с точки зрения таких факторов, как производительность, использование памяти, простота кодирования, правильные действия и т. Д.

Обновление : В одном конкретном приложении я обнаружил, что без переноса DataContext в блок использования объем памяти продолжал увеличиваться, поскольку живые объекты не были выпущены для 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 без использования и поддерживается

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

    return q.toList(); 

Спасибо.

Ответы [ 5 ]

11 голосов
/ 19 февраля 2010

Создание DataContext может быть дорогим по сравнению с другими вещами.Однако, если вы закончили с этим и хотите, чтобы соединения были закрыты как можно скорее, это будет сделано, высвобождая любые кэшированные результаты также из контекста.Помните, что вы создаете его, несмотря ни на что, в этом случае вы просто сообщаете сборщику мусора, что есть больше бесплатных вещей, от которых нужно избавиться.

DataContext создан для использования в качестве объекта короткого использования, используйте его,получить единицу работы, уйти ... это именно то, что вы делаете с использованием.

Итак, преимущества:

  • Более быстрые закрытые соединения
  • Освободить память от удаления (Кэшированные объекты в содержимом)

Недостатки - больше кода?Но это не должно быть сдерживающим фактором, вы правильно используете using.

Посмотрите здесь ответ Microsoft: http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/2625b105-2cff-45ad-ba29-abdd763f74fe

Короткая версия, если вам нужно использовать using / .Dispose():

Краткий ответ;нет, не обязательно, но вы должны ...

5 голосов
/ 19 марта 2010
  1. Первый раз DataContext получит объект из БД.
  2. В следующий раз, когда вы запустите запрос, чтобы получить тот же объект (те же параметры). Вы увидите запрос в профилировщике, но ваш объект в DataContext не будет заменен новым из БД !!

Не говоря уже о том, что за каждым DataContext стоит карта идентификации всех объектов, которые вы запрашиваете у БД (вы не хотите хранить это).

Полная идея DataContext: Единица работы с Оптимистичный параллелизм . Используйте его для короткой транзакции (только одна отправка) и распоряжайтесь.

Лучший способ не забыть утилизировать - использовать ().

5 голосов
/ 19 февраля 2010

Ну, это IDisposable, так что я думаю, это неплохая идея. Люди из MSFT говорят, что они сделали DataContexts как можно более легким, чтобы вы могли создавать их с опрометчивой энергией, так что вы, вероятно, не получите много, хотя .....

3 голосов
/ 19 февраля 2010

Я зависит от сложности вашего уровня данных. Если каждый вызов представляет собой простой одиночный запрос, то каждый вызов может быть заключен в «Использование», как в вашем вопросе, и это будет хорошо.

Если, с другой стороны, ваш уровень данных может ожидать нескольких последовательных вызовов от бизнес-уровня, вам придется многократно создавать / использовать 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
    }
}
1 голос
/ 06 марта 2010

В одном конкретном приложении я обнаружил, что без переноса блока DataContext в using объем используемой памяти продолжал увеличиваться, поскольку живые объекты не были выпущены для GC. Как в приведенном ниже примере, если я держу ссылку на объект List<Table> и объекты доступа 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
}

Учитывая этот пример, я не могу утилизировать текст данных, потому что все Table экземпляры в переменной списка qs ** имеют один и тот же текст данных . После Dispose() доступ к объекту в process(Table q) вызывает исключение уже обработанного текста данных.

Ужасный клубник, для меня, должен был удалить все ссылки на сущности для объектов q после цикла foreach. Лучше всего, конечно, использовать оператор using.

Что касается моего опыта, я бы сказал, используйте выражение using.

...