代码之家  ›  专栏  ›  技术社区  ›  zerkms

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

  •  7
  • zerkms  · 技术社区  · 16 年前

    Linq2SQL使用(在ASP.NET MVC应用程序中)时的首选做法是:为创建“singleton” DataContext 像:

    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())
    {
        ...
    }
    

    使用 使用 给代码带来了一些限制。所以我更喜欢用单件的。这是奇怪的练习吗?

    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-我可以继续编写查询而不执行它,所以这里只返回懒惰的结果。
    如果我用 使用 -我不能返回iqueryable(因为db将被释放,iqueryable也将丢失),我将把它更改为list。现在这个方法将返回“巨大的”列表,我将从中过滤前一个函数的数据。

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

    3 回复  |  直到 16 年前
        1
  •  5
  •   LorenVS    16 年前

    LINQ to SQL数据上下文不是线程安全的,应该只在单个线程的上下文中使用。使用singleton模式不仅与标准的linq2sql实践相反,而且如果应用程序遇到任何严重的负载,都会导致严重的问题。

    编辑:

    为了响应您对using块的限制,请尝试将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块内的方法:

    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个数据上下文,如果您正在数据库上执行4个操作,则将打开4个sqlconnections。但是,请记住.NET使用的是SQL Server连接池,因此每个操作不需要创建全新的SQL连接,而只需要从连接池中检索现有的连接并重新打开连接。

        2
  •  2
  •   Jarret Raim    16 年前

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

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

        3
  •  0
  •   Ian Mercer    16 年前

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

    谷歌搜索“web范围的objectcontext”或“objectcontext lifetime”(或L2s的dataContext)。

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

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