Срок службы класса Linq to SQL - PullRequest
       37

Срок службы класса Linq to SQL

4 голосов
/ 13 октября 2008

Насколько я понимаю, когда я создаю Linq для класса SQL , это эквивалентно новому SqlConnection объекту .

Предположим, у меня есть объект с двумя методами: Delete() и SubmitChanges(). Было бы мудро с моей стороны обновить класс Linq to SQL в каждом из методов, или будет частная переменная, содержащая класс Linq to SQL - new'ed вверх конструктор - будет путь?

То, что я пытаюсь избежать, это тайм-аут.

UPDATE:

namespace Madtastic
{
    public class Comment
    {
        private Boolean _isDirty = false;
        private Int32 _id = 0;
        private Int32 _recipeID = 0;
        private String _value = "";
        private Madtastic.User _user = null;

        public Int32 ID
        {
            get
            {
                return this._id;
            }
        }

        public String Value
        {
            get
            {
                return this._value;
            }

            set
            {
                this._isDirty = true;

                this._value = value;
            }
        }

        public Madtastic.User Owner
        {
            get
            {
                return this._user;
            }
        }


        public Comment()
        {
        }


        public Comment(Int32 commentID)
        {            
            Madtastic.DataContext mdc = new Madtastic.DataContext();

            var comment = (from c in mdc.Comments
                           where c.CommentsID == commentID
                           select c).FirstOrDefault();

            if (comment != null)
            {
                this._id = comment.CommentsID;
                this._recipeID = comment.RecipesID;
                this._value = comment.CommentsValue;
                this._user = new User(comment.UsersID);
            }

            mdc.Dispose();
        }


        public void SubmitChanges()
        {
            Madtastic.DataContext mdc = new Madtastic.DataContext();


            var comment = (from c in mdc.Comments
                           where c.CommentsID == this._id
                           select c).FirstOrDefault();

            if (comment != null && this._isDirty)
            {
                comment.CommentsValue = this._value;
            }
            else
            {
                Madtastic.Entities.Comment c = new Madtastic.Entities.Comment();

                c.RecipesID = this._recipeID;
                c.UsersID = this._user.ID;
                c.CommentsValue = this._value;

                mdc.Comments.InsertOnSubmit(c);
            }


            mdc.SubmitChanges();


            mdc.Dispose();
        }


        public void Delete()
        {
            Madtastic.DataContext mdc = new Madtastic.DataContext();

            var comment = (from c in mdc.Comments
                           where c.CommentsID == this._id
                           select c).FirstOrDefault();

            if (comment != null)
            {
                mdc.Comments.DeleteOnSubmit(comment);

                mdc.SubmitChanges();

                this._isDirty = false;
                this._id = 0;
                this._recipeID = 0;
                this._value = "";
                this._user = null;
            }

            mdc.Dispose();
        }
    }
}

РЕФАКТОРНЫЙ КОД (согласно спецификации Гранка):

namespace Madtastic
{
    public sealed class CommentNew : IDisposable
    {
        private Madtastic.DataContext _mdc;
        private Madtastic.Entities.Comment _comment;
        private Madtastic.User _user;


        public Int32 ID
        {
            get
            {
                return this._comment.CommentsID;
            }
        }

        public String Value
        {
            get
            {
                return this._comment.CommentsValue;
            }

            set
            {
                this._comment.CommentsValue = value;
            }
        }

        public Madtastic.User Owner
        {
            get
            {
                return this._user;
            }
        }


        public void Comment(Int32 commentID)
        {
            this._mdc = new Madtastic.DataContext();

            this._comment = (from c in _mdc.Comments
                             where c.CommentsID == commentID
                             select c).FirstOrDefault();

            if (this._comment == null)
            {
                this._comment = new Madtastic.Entities.Comment();

                this._mdc.Comments.InsertOnSubmit(this._comment);
            }
            else
            {
                this._user = new Madtastic.User(this._comment.User.UsersID);
            }
        }


        public void SubmitChanges()
        {
            this._mdc.SubmitChanges();
        }


        public void Delete()
        {
            this._mdc.Comments.DeleteOnSubmit(this._comment);

            this.SubmitChanges();
        }


        void IDisposable.Dispose()
        {
            this._mdc.Dispose();
        }
    }
}

Ответы [ 5 ]

2 голосов
/ 14 октября 2008

Теперь, рассмотрев пример кода, который вы отредактировали для публикации, я определенно реорганизовал бы ваш класс, чтобы воспользоваться встроенной функциональностью LINQ-to-SQL. (Я не буду редактировать свой предыдущий комментарий, потому что это лучший ответ на общий вопрос)
Поля вашего класса выглядят довольно прямым отображением столбцов таблицы комментариев в базе данных. Поэтому вам не нужно делать большую часть того, что вы делаете вручную в этом классе. Большая часть функциональности может быть обработана, просто имея закрытый член типа Madtastic.Entities.Comment (и просто сопоставляя ваши свойства с его свойствами, если вам нужно поддерживать, как этот класс взаимодействует с остальной частью проекта). Тогда ваш конструктор может просто инициализировать закрытый член Madtastic.DataContext и установить свой закрытый член Madtastic.Entities.Comment на результат запроса LINQ. Если комментарий нулевой, создайте новый и вызовите InsertOnSubmit для DataContext. (но пока нет смысла отправлять изменения, потому что вы все равно не задали никаких значений для этого нового объекта).
В ваших SubmitChanges все, что вам нужно сделать, это вызвать SubmitChanges для DataContext. Он отслеживает, нужно ли обновлять данные, он не попадет в базу данных, если это не так, поэтому вам не нужен _isDirty.
В вашем Delete () все, что вам нужно сделать, это вызвать DeleteOnSubmit для DataContext.
В результате небольшого обзора вы можете обнаружить, что вам вообще не нужен класс Madtastic.Comment, а класс LINQ-to-SQL Madtastic.Entities.Comment может действовать непосредственно как уровень доступа к данным. Кажется, что единственными практическими отличиями являются конструктор, который принимает commentID, и тот факт, что Entities.Comment имеет свойство UsersID, где у вашего класса Madtastic.Comment есть целый пользователь. (Однако, если User также является таблицей в базе данных, а UsersID является внешним ключом своего первичного ключа, вы обнаружите, что LINQ-to-SQL создал объект User в объекте Entities.Comment, к которому вы можете обращаться напрямую с комментарием. Пользователь)
Если вы обнаружите, что можете полностью исключить этот класс, это может означать, что вы можете дополнительно оптимизировать жизненный цикл вашего DataContext, добавив его в методы вашего проекта, использующие Comment.

Отредактировано для публикации следующего примера измененного кода (извиняюсь за любые ошибки, поскольку я набрал его в блокноте за пару секунд вместо того, чтобы открывать Visual Studio, и я все равно не получил бы intellisense для вашего проекта):

namespace Madtastic
{
    public class Comment
    {
        private Madtastic.DataContext mdc;
        private Madtastic.Entities.Comment comment;

        public Int32 ID
        {
            get
            {
                return comment.CommentsID;
            }
        }

        public Madtastic.User Owner
        {
            get
            {
                return comment.User;
            }
        }

        public Comment(Int32 commentID)
        {            
            mdc = new Madtastic.DataContext();

            comment = (from c in mdc.Comments
                           where c.CommentsID == commentID
                           select c).FirstOrDefault();

            if (comment == null)
            {
                comment = new Madtastic.Entities.Comment();
            mdc.Comments.InsertOnSubmit(comment);
            }

        }

        public void SubmitChanges()
        {

            mdc.SubmitChanges();

        }


        public void Delete()
        {
            mdc.Comments.DeleteOnSubmit(comment);
            SubmitChanges();
        }
    }
}

Возможно, вы также захотите внедрить IDisposable / использовать, как предложили несколько человек.

2 голосов
/ 13 октября 2008

Зависит от того, что вы называете «классом LINQ-to-SQL», и как выглядит рассматриваемый код.
Если вы говорите об объекте DataContext, и ваш код является классом с большим временем жизни или самой программой, я считаю, что было бы лучше инициализировать его в конструкторе. На самом деле это не то же самое, что создание и / или открытие нового SqlConnection, на самом деле он очень умный в управлении своим пулом соединений с базой данных, параллелизмом и целостностью, поэтому вам не нужно об этом думать, это часть моего опыта с LINQ к SQL. Я никогда не видел проблемы с тайм-аутом.
Одна вещь, которую вы должны знать, это то, что очень трудно совместно использовать объекты таблиц в области действия DataContext, и это действительно не рекомендуется, если вы можете избежать этого. Detach () и Attach () могут быть стервозными. Поэтому, если вам нужно передать объект LINQ-to-SQL, представляющий строку в таблице в вашей базе данных SQL, вы должны попытаться спроектировать жизненный цикл объекта DataContext, чтобы охватить всю работу, которую вы должны выполнить над любым объектом. это выходит из этого.
Кроме того, есть много накладных расходов, связанных с созданием объекта DataContext, и много накладных расходов, которыми он управляет ... Если вы снова и снова сталкиваетесь с одними и теми же таблицами, было бы лучше использовать один и тот же экземпляр DataContext. , поскольку он будет управлять своим пулом соединений, а в некоторых случаях кешировать некоторые вещи для эффективности. Тем не менее, рекомендуется не загружать в DataContext все таблицы в вашей базе данных, а только те, которые вам нужны, и если таблицы, к которым осуществляется доступ, очень раздельны в совершенно разных обстоятельствах, вы можете рассмотреть возможность их разделения на несколько DataContexts, что дает вам некоторые варианты, когда вы инициализируете каждый, если обстоятельства, окружающие их, отличаются.

0 голосов
/ 14 октября 2008

SqlConnections объединяются по умолчанию. Вы должны обновить их, чтобы оправдать такую ​​стоимость!

DataContexts дешево сделать (после первого). Вы должны собрать их в кучу, чтобы оправдать первую стоимость нового!

0 голосов
/ 14 октября 2008

Один из моих текущих проектов использует Linq to SQL, где мы храним текст данных как личное поле внутри объекта. В большинстве случаев это не доставляло хлопот, допускало насмешки в будущем, если я передал текстовый текст в конструкторе, и казалось бы, чище, чем открывать несколько текстовых данных. Подобно тому, что упоминал Джейкоб выше, мы реализуем IDisposable, чтобы гарантировать, что текст данных может быть надежно закрыт, когда объект больше не нужен.

0 голосов
/ 13 октября 2008

Я предполагаю, что вы имеете в виду хранение значения для класса DataContext? Лично я предпочитаю использовать по умолчанию предложение "using" для всего, что является IDisposable (каковы классы DataContext). Создание экземпляра в конструкторе и удержание DataContext в закрытой переменной сделало бы это невозможным. Так что для меня я бы поставил инстанцирование в методах, но более конкретно, я бы поставил инстанцирование в предложении использования, чтобы обеспечить надлежащее удаление.

...