【问题标题】:Linq to SQL class lifespanLinq to SQL 类的生命周期
【发布时间】:2008-10-13 17:18:55
【问题描述】:

据我所知,当我新建一个 Linq to SQL 类时,它相当于新建一个 SqlConnection 对象

假设我有一个具有两种方法的对象:Delete()SubmitChanges()。在每个方法中更新 Linq to SQL 类 对我来说是明智之举,还是有一个保存 Linq to SQL 类的私有变量 - 更新了由构造函数 - 是要走的路吗?

我要避免的是超时。

更新:

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();
        }
    }
}

重构代码(根据 Grank 的规范):

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();
        }
    }
}

【问题讨论】:

    标签: c# linq-to-sql oop c#-3.0


    【解决方案1】:

    现在查看了您编辑后发布的代码示例,我肯定会重构您的类以利用 LINQ-to-SQL 的内置功能。 (我不会编辑我之前的评论,因为它是对一般问题的更好回答)
    您的类的字段似乎是数据库中 Comments 表上列的非常直接的映射。因此,您不需要在本课程中手动完成大部分手动操作。大多数功能只需拥有一个 Madtastic.Entities.Comment 类型的私有成员即可处理(如果您必须维护此类与项目其余部分的交互方式,只需将您的属性映射到其属性)。然后您的构造函数只需初始化一个私有成员 Madtastic.DataContext 并将您的私有成员 Madtastic.Entities.Comment 设置为对其进行 LINQ 查询的结果。如果注释为空,则创建一个新注释并在 DataContext 上调用 InsertOnSubmit。 (但提交更改还没有意义,因为您还没有为这个新对象设置任何值)
    在您的 SubmitChanges 中,您所要做的就是在 DataContext 上调用 SubmitChanges。它会自行跟踪数据是否需要更新,如果不需要,它不会访问数据库,因此您不需要 _isDirty。
    在您的 Delete() 中,您只需在 DataContext 上调用 DeleteOnSubmit。
    事实上,稍微回顾一下,您可能会发现根本不需要 Madtastic.Comment 类,而 Madtastic.Entities.Comment LINQ-to-SQL 类可以直接充当您的数据访问层。似乎唯一的实际区别是采用 commentID 的构造函数,以及 Entities.Comment 具有 UsersID 属性的事实,而您的 Madtastic.Comment 类具有整个 User。 (但是,如果 User 也是数据库中的一个表,并且 UsersID 是其主键的外键,您会发现 LINQ-to-SQL 在 Entities.Comment 对象上创建了一个 User 对象,您可以直接访问它带评论。用户)
    如果你发现你可以完全消除这个类,这可能意味着你可以进一步优化 DataContext 的生命周期,方法是将它提升到项目中使用 Comment 的方法。

    编辑后发布以下示例重构代码(对任何错误表示歉意,因为我在几秒钟内在记事本中输入了它,而不是打开 Visual Studio,而且无论如何我都不会为您的项目获得智能感知):

    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/using。

    【讨论】:

    • 哇...只是...哇!放下我在这里得到的最佳答案。明天我会试试这个。太棒了,格兰克! :)
    • 没问题!我真的很喜欢 LINQ,而且我可能并不总是有正确的答案,所以我很喜欢堆栈溢出来学习它,因为我很快就会发现我是否错了! LINQ-to-SQL 对我们来说太新了,我想很多人自然仍然在以 ADO.NET 的方式看待它。
    • “使用”的东西是什么?我不明白:)
    • using 关键字是一种确保一次性对象在您用完后得到妥善处理的方法。看到这个线程:stackoverflow.com/questions/75401/uses-of-using-in-c
    • 我无法弄清楚“使用”究竟会在哪里产生影响。看看我更新的代码,告诉我你的想法。将不胜感激。
    【解决方案2】:

    取决于“LINQ-to-SQL 类”所指的内容以及相关代码的外观。
    如果您正在谈论 DataContext 对象,并且您的代码是一个生命周期较长的类或您的程序本身,我相信最好在构造函数中对其进行初始化。这并不像创建和/或打开一个新的 SqlConnection,它实际上非常聪明地管理其数据库连接池以及并发性和完整性,因此您无需考虑它,这是我迄今为止体验的一部分乐趣LINQ 到 SQL。我从未见过发生超时问题。
    您应该知道的一件事是,跨 DataContext 范围共享表对象非常困难,如果可以避免的话,真的不建议这样做。 Detach() 和 Attach() 可能很糟糕。因此,如果您需要传递代表 SQL 数据库表中一行的 LINQ-to-SQL 对象,您应该尝试设计 DataContext 对象的生命周期,以涵盖您需要对任何对象执行的所有工作从中产生的。
    此外,实例化 DataContext 对象会产生大量开销,并且由它管理大量开销......如果您一遍又一遍地访问相同的几个表,最好使用相同的 DataContext 实例,因为它将管理其连接池,并在某些情况下缓存一些东西以提高效率。但是,建议不要将数据库中的每个表都加载到 DataContext 中,只加载您需要的表,如果正在访问的表在非常独立的情况下非常独立,您可以考虑将它们拆分为多个 DataContext,这样可以为您提供一些如果围绕它们的情况不同,则有关何时初始化每个选项的选项。

    【讨论】:

      【解决方案3】:

      我假设您的意思是为 DataContext 类保存一个值?就个人而言,我的偏好是默认为任何 IDisposable(DataContext 类是)的“使用”子句。在构造函数中实例化并将 DataContext 保存在私有变量中将使这成为不可能。所以对我来说,我会将实例化放在方法中,但更具体地说,我会将实例化放在 using 子句中,以便确保正确处理。

      【讨论】:

        【解决方案4】:

        我目前的一个项目使用 Linq to SQL,我们将数据上下文作为对象内部的私有字段保存。这样做在大多数情况下并不麻烦,如果我在构造函数中传入数据上下文,则允许将来进行模拟,并且看起来比打开多个数据上下文更干净。与 Jacob 上面提到的类似,我们正在实现 IDisposable 以确保在不再需要对象时可以可靠地关闭数据上下文。

        【讨论】:

          【解决方案5】:

          SqlConnections 默认是池化的。你应该更新它们以证明汇集成本是合理的!

          DataContext 制作起来很便宜(在第一个之后)。你应该更新它们以证明第一个新的成本是合理的!

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2010-12-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多