如何在web应用程序中集中实体框架数据上下文

本文关键字:实体 框架 数据 上下文 集中 web 应用程序 | 更新日期: 2023-09-27 18:02:44

在我们的应用程序中,我们使用存储库模式从数据存储介质检索和持久化数据。我们选择使用的媒介是实体框架4。这似乎是一种非常干净的做事方式,99%的情况下都很有效。

现在我们遇到了一个问题。我们有两个存储库,如下所示:

public class UserRepository : IUserRepository
{
    Entities dataContext = new Entities();
    public User GetUser(string username)
    {
        return dataContext.Users.SingleOrDefault(x => x.Username == username);
    }
    // ... more CRUD-style methods that are not relevant to this question.
    public void SaveChanges()
    {
        dataContext.SaveChanges();
    }
}
public RoleRepository : IRoleRepository
{
    Entities dataContext = new Entities();
    public Role GetRole(string name)
    {
        return dataContext.Roles.SingleOrDefault(x => x.Name == name);
    }
    // ... more CRUD-style methods that are not relevant to this question.
    public void SaveChanges()
    {
        dataContext.SaveChanges();
    }
}
在实体框架模型中,用户和角色实际上具有多对多的关系。有时,我们希望使用现有用户和现有角色,并将两者关联起来。通常情况下,如果您编写像这样的简短示例代码片段,则效果会很好:
Entities dataContext = new Entities();
Role roleToAdd = dataContext.Roles.Single(x => x.Name == "Admin");
User user = dataContext.Users.Single(x => x.Username == "Fred");
user.Roles.Add(roleToAdd);
dataContext.SaveChanges();

这非常有效,因为两个实体都是从同一个EF数据上下文对象中检索的。但是,在我们的应用程序中,每个存储库创建自己的数据上下文对象。所以当我们尝试用我们自己的架构做同样的事情时:

UserRepository userRepo = new UserRepository();
RoleRepository roleRepo = new RoleRepository();
User user = userRepo.GetUser("Fred");
Role roleToAdd = roleRepo.GetRole("Admin");
user.Roles.Add(roleToAdd);
userRepo.SaveChanges();

我们得到这个错误:

不能定义两个对象之间的关系,因为它们附加到不同的ObjectContext对象。

集中这个数据上下文的最佳方法是什么?显然,我不想在UserRepository中复制GetRole方法,因为那样会显得多余和愚蠢。我可以在UserRepository上执行一个更详细的方法,该方法接受用户名和用户名,然后使用相同的数据上下文来检索和关联它们,如下所示:

public void AddUserToRole(string username, string role)
{
    User user = dataContext.Users.Single(x => x.Username == username);
    Role roleToAdd = dataContext.Roles.Single(x => x.Name == role);
    user.Roles.Add(roleToAdd);
}

我可以直接写:

userRepo.AddUserToRole("Fred", "Admin");
userRepo.SaveChanges();

但这是最好的方法吗?是否有更好的方法将EF数据上下文集中在每个请求上,以便所有存储库使用相同的数据上下文,而不是创建自己的数据上下文?如果有,我该怎么做?

如何在web应用程序中集中实体框架数据上下文

在存储库上使用构造函数注入来传递上下文。

public class UserRepository : IUserRepository
{
    Entities dataContext;
    public UserRepository(Entities entities)
    {
       this.dataContext = entities;
    }
    public User GetUser(string username)
    {
        return dataContext.Users.SingleOrDefault(x => x.Username == username);
    }
    // ... more CRUD-style methods that are not relevant to this question.
    public void SaveChanges()
    {
        dataContext.SaveChanges();
    }
}

告诉您的DI容器将上下文生命周期设置为请求作用域。

。,使用AutoFac,您将:

builder.RegisterType<Entities>().InstancePerHttpRequest();
builder.RegisterType<UserRepository>().As<IUserRepository>().InstancePerHttpRequest();
builder.RegisterControllers(typeof(MvcApplication).Assembly);

我们遇到了完全相同的问题。您应该使用工作单元设计模式。阅读更多:http://blogs.msdn.com/b/adonet/archive/2009/06/16/using-repository-and-unit-of-work-patterns-with-entity-framework-4-0.aspx

我个人更喜欢传递用户名和角色的方法,它具有存储库中用于向数据库添加用户的所有db逻辑。如果您调用此方法10次,您不会希望在MVC应用程序中的10个不同位置获取角色并将其添加到用户对象中。

让存储库完成所有的工作。