LinqToSql声明并实例化DataContext的最佳实践?

时间:2009-02-14 17:23:13

标签: .net vb.net linq-to-sql datacontext

在我的扩展LinqToSql类中设置DataContext以便轻松访问方面,最佳做法是什么?

例如,我的dbml中有一个“User”实体,我想像这样向该类添加方法:

Partial Public Class User

    Public Function GetUser(ByVal UserID as Integer) as User
         'Do Work
    End Function

End Class

为了访问我的DataContext,我必须在方法中声明它,如下所示:

Partial Public Class User

    Public Function GetUser(ByVal UserID as Integer) as User
         Dim dc as New MyDataContext()
         Return (From u in dc.Users Where u.ID = UserID).Single()
    End Function

End Class

我不想为每一种方法都这样做。通常(如果我没有扩展LinqToSql dbml类)我可以这样做:

Partial Public Class User
    Private dc as MyDataContext

    Public Sub New()
         dc = new MyDataContext()
    End Sub

    Public Function GetUser(ByVal UserID as Integer) as User
         Return (From u in dc.Users Where u.ID = UserID).Single()
    End Function

    Public Function GetAllUsers() as IEnumerable(Of User)
         Return From u in dc.Users
    End Function

    'etc...

End Class

这将允许我访问每个方法的datacontext,而不必每次都重新声明它。但是当然你不能这样做,因为dbml已经有了一个构造函数。如果有任何变化,将代码添加到dbml中总会被覆盖。

任何人都对如何在这里保存一些多余的代码有任何好的想法?

TIA!

5 个答案:

答案 0 :(得分:14)

首先,确保在完成后处理DataContext!他可能是一个沉重的小混蛋(编辑不会沉重的实例化,但如果你继续使用它而不进行处理,那就很难保持);你不希望旧的DataContexts在内存中闲逛。

其次, DataContext旨在表示单个逻辑事务。例如。您应该在每次要开始新事务时创建一个新事务,并在 事务完成时删除它。因此,出于您的目的,可能是 GetUser方法的范围。如果你有一系列需要作为一个组进行的数据库调用,他们都应该使用相同的DC,然后再删除它。

答案 1 :(得分:12)

作为Rex M said,datacontext旨在为每个逻辑事务实例化,使用和处理。像这样的模式有时被称为“工作单元”。

执行此操作的最常见方式(即我知道)是在using块中实例化datacontext。我有一段时间没有使用VB,但看起来应该是这样的:

Using dc As New MyDataContext()
   user = (From u in dc.Users Where u.ID = UserID).Single()
End Using

这不仅加强了事务/工作单元的外观(通过代码的物理形状),而且确保在块结束时在datacontext上调用Dispose()。

请参阅this MSDN page

  

通常,DataContext实例设计为持续一个“单位”   工作“但你的应用程序定义   那个词。 DataContext是   轻便且不贵   创建。典型的LINQ to SQL   应用程序创建DataContext   方法范围或实例   昙花一现的成员   代表一组相关的逻辑   数据库操作。

答案 2 :(得分:0)

我想也许真正的问题是User可能不是实例成员调用GetUser的正确位置。

答案 3 :(得分:0)

我认为,有几种不同的方法可以解决这个问题。首先,您可以使用存储库模式来查询存储库中的对象,它会转到数据库,检索对象 - 可能会将其从数据上下文中分离出来,或者根据存储库的实现保持数据上下文 - 并将它返回给你。对象的工厂方法将位于存储库中,而不是实体本身。您可能使用反射和泛型来最小化必须实现的方法的数量并将代码保持干燥。

另一种方式,以及LINQtoSQL原本用于IMHO的方式是为您打算执行的每组数据库操作创建数据上下文。在这种情况下,数据上下文的创建也发生在实体之外,通常在使用实体的类中,而不是在数据层中。您还可以向数据上下文添加方法 - 使您的实际数据上下文抽象并从中继承 - 再次使用反射,执行一些常见的检索功能,以便您不必重复它们。您可能必须使用像ActiveRecords这样的数据库模式,其中id列始终具有相同的名称以使其工作。

另一方面,您可以查看使用nHibernate或Castle的ActiveRecord,而不是在您自己的解决方案中复制上述任何一项。

答案 4 :(得分:0)

如果单独保留User类并允许IDE处理它的创建,可能会更容易。

通常我更喜欢让一个单独的类处理数据检索。假设您将其称为UserDataProvider,并且所有获取User实例的调用最终都会通过此类。

UserDataProvider的构造函数可以实例化数据上下文对象的全局实例以供重用。它看起来像这样(在C#和未经测试的代码中,所以请耐心等待):

public class UserDataProvider 
{
    private UserDataContext _data = null;

    public UserDataProvider()
    {
        _data = new UserDataContext();
    }

    public User GetUser(int userID)
    {
        return _data.Users.FirstOrDefault(u => u.UserID == userID);
    }
}

或者,您可以在属性中放置初始化并访问该属性以进行数据上下文使用。

public class UserDataProvider 
{
    private UserDataContext _dataContext;

    private UserDataContext DataContext 
    {
        get
        {
            if (_data == null)
                _data = new UserDataContext();

            return _data;
        }
    }

    public User GetUser(int userID)
    {
        return DataContext.Users.FirstOrDefault(u => u.UserID == userID);
    }
}