LinqToSql声明和实例化DataContext的最佳实践是什么?

15

在我的扩展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
这将允许我在每个方法中不必重新声明数据上下文即可访问它。但是,当然你不能这样做,因为dbml已经有一个构造函数了。而且,如果有任何更改,向dbml中添加代码总是会被覆盖掉。
有没有人有什么好主意可以帮我减少一些多余的代码?
谢谢!
5个回答

15

首先,确保在使用完后处理你的DataContext!它可能会变得很臃肿 (编辑 实例化时不会变得很臃肿,但如果你不处理它并继续使用它,它会变得很难处理)。你不希望旧的DataContexts存留在内存中。

其次,DataContext旨在表示单个逻辑事务。例如,每次想要开始新事务时应该创建一个新的DataContext,并在事务完成时将其丢弃。所以对于你的目的来说,这可能GetUser方法的范围。如果你有一系列需要作为一组进行的DB调用,它们应该在丢弃它之前都使用同一个DC。


1
数据上下文本身实际上非常轻量级,尽管它可能引用了很多实体。释放它以释放这些实体是一个非常好的想法。如果它是一个重量级对象,我会更倾向于保留它,这样我就不必重新创建它。 - tvanfosson
反对使用Dispose的论点:http://stephenwalther.com/blog/archive/2008/08/20/asp-net-mvc-tip-34-dispose-of-your-datacontext-or-don-t.aspx - Peter Hedberg
@Palpie,这还好,直到你的网站开始崩溃,因为你得到了足够的流量,以至于“最终清理”不再起作用。 - Rex M
1
我个人更喜欢使用using语句,主要是因为我认为它增加了可读性。只是想补充一些其他的论点。 - Peter Hedberg
1
更多人的见解:http://www.whitneyland.com/2008/06/linq-datacontex.html,还有一个相关问题:https://dev59.com/THRC5IYBdhLWcg3wKtz2。 - Benjol
显示剩余2条评论

13
Rex M所说,数据上下文旨在为每个逻辑事务实例化、使用和处理。这样的模式有时被称为“工作单元”。
我知道的最常见的方法(是)使用using块实例化您的数据上下文。我已经有一段时间没有用VB了,但它应该看起来像这样:
Using dc As New MyDataContext()
   user = (From u in dc.Users Where u.ID = UserID).Single()
End Using

这不仅通过代码的物理形态加强了事务/工作单元的外观,而且还确保在块结束时调用Dispose()释放您的数据上下文。

请参见此MSDN页面

通常,DataContext实例被设计为持续一个“工作单元”,无论您的应用程序如何定义该术语。DataContext是轻量级的,创建成本不高。典型的LINQ to SQL应用程序在方法范围内或作为短寿命周期类的成员创建DataContext实例,这些类表示一组相关数据库操作。


0

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


你是什么意思?你能再解释一下吗? - RichC

0

有几种不同的方法可以实现这个,我认为这些都是很好的实践。首先,您可以使用存储库模式,在其中查询存储库以获取对象,它会访问数据库,检索对象--可能从数据上下文中分离或保留数据上下文,具体取决于存储库的实现--并将其返回给您。对象的工厂方法将在存储库上,而不是实体本身上。您可能会使用反射和泛型来最小化需要实现的方法数量,并使代码保持DRY。

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

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

0

如果您让 IDE 处理其创建,可能会更容易,而不是改变 User 类。

通常我更喜欢一个单独的类处理数据检索。比如你可以将它称为 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);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接