linq2sql:单例或使用,最佳实践

时间:2010-04-14 23:22:39

标签: linq-to-sql singleton

linq2sql使用时(在asp.net mvc应用程序中)的首选做法是:为DataContext创建“singleton”,如:

partial class db
{
    static db _db = new db(global::data.Properties.Settings.Default.nanocrmConnectionString, new AttributeMappingSource());

    public static db GetInstance()
    {
        return _db;
    }
}

或在using内需要时检索新实例:

using (db _db = new db())
{
    ...
}

using的使用会给代码带来一些限制。所以我更喜欢使用单身之一。是不是很奇怪?

UPD
解释为什么我使用单身:

public class UserGroupRepository
{
    public static IQueryable<Group> RolesFor(string username)
    {
        User user = UserRepository.WithUsername(username);

        return from g in db.GetInstance().Groups
                join ug in db.GetInstance().UsersGroups on g.Id equals ug.GroupId
                where ug.UserId == user.Id
                select g;
    }
}
我有这种方法。由于它返回IQueryable - 我可以继续编写查询而不执行它,所以这里只是懒惰的结果返回 如果我用using重写相同的代码 - 我无法返回IQueryable(因为db将被丢弃并且IQueryable也会丢失),我会将其更改为List。现在这个方法将返回“巨大的”List,我将从中过滤前一个函数的数据。

我希望我描述得足够详细。

3 个答案:

答案 0 :(得分:5)

Linq to Sql数据上下文不是线程安全的,只应在单个线程的上下文中使用。使用单例模式不仅违反了标准的linq2sql实践,而且如果您的应用程序遇到任何严重的负载,也会导致严重的问题。

修改

为了回应您对使用块的限制,请尝试将RolesFor方法实现为扩展方法:

public static IQueryable<Group> GetUserRoles(this Database db, string username)
{
        return from g in db.GetInstance().Groups
                join ug in db.GetInstance().UsersGroups on g.Id equals ug.GroupId
                where ug.UserId == user.Id
                select g;
}

这将允许您从任何地方在使用块内调用您的方法:

using(Database db = createContext())
{
     IQueryable<Group> queryable = db.GetUserRoles("MyUsername");
     // from here on you can query the queryable object
     var groups = (from g in queryable
                   where g.Name == "MyRole"
                   select g).ToList();
}

编辑2

响应您关于为数据上下文的每个实例打开与sql server的另一个连接的注释。创建datacontext不会打开与sql server的连接,但每个实际操作都会。无论您是创建1个还是4个datacontexts,如果您在数据库上执行4个操作,将打开4个sqlconnections。但是,请记住,.NET使用sql server连接池,因此每个操作不需要创建全新的SqlConnection,而只需要从连接池中检索现有的连接池并重新打开连接

答案 1 :(得分:2)

Linq to SQL希望您为每个操作创建一个上下文。实际上,只能为执行第一个查询设置数据加载选项,因此如果要加载提示,则必须这样做。但是,当您拥有3层体系结构时,您将遇到以下问题:来自一个datacontext的对象无法真正处理来自不同上下文的对象。

解决这个问题真是太痛苦了,所以我们只针对Web服务的请求和Windows服务等的线程本地方法做了上下文。

答案 2 :(得分:0)

您可能希望管理上下文的生命周期,将其范围限定为单个Web请求,并且在该Web请求周期的生命周期内只有一个上下文。

Google搜索“web scoped objectcontext”或“objectcontext lifetime”(或l2s的datacontext)。

e.g。 http://dotnetslackers.com/articles/ado_net/Managing-Entity-Framework-ObjectContext-lifespan-and-scope-in-n-layered-ASP-NET-applications.aspx

在MVC2中,您可以将上下文管理代码放在基本控制器类中。