关于c#:在MVC中按请求使用Owin DbContext的实体框架

Entity Framework with Owin DbContext per request in MVC

我注意到,当使用单个用户帐户时,MVC的项目模板将一些对象放在当前的OWIN上下文中(在App_Start/Startup.Auth.cs中):

1
2
3
4
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);

看起来这是为了访问数据库中的标识功能。我的理解是,每个请求创建一个ApplicationDbContext实例,并在整个管道中重复使用。在我自己的实体框架DbContext中这样做是否有益?

例如,我在App_Start/Startup.Data.cs中创建了一个新文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public partial class Startup
{

    public void ConfigureData(IAppBuilder app)
    {

        app.CreatePerOwinContext(CreateParkingEntities);

    }

    protected ParkingEntities CreateParkingEntities()
    {
        return new ParkingEntities();
    }

}

然后在Startup.cs中:

1
2
3
4
5
6
7
8
public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        ConfigureAuth(app);
        ConfigureData(app);
    }
}

然后我可以在控制器中使用上下文:

1
2
3
4
5
6
7
8
9
10
11
12
13
private ParkingEntities _db;

public ParkingEntities DbContext
{
    get
    {
        return _db ?? HttpContext.GetOwinContext().Get<ParkingEntities>();
    }
    private set
    {
        _db = value;
    }
}

我认为如果这是标准实践,那么实体框架将为此提供一些框架,但它只是在控制器级别创建一个实例。假设仅从该控制器访问DbContext是否安全,那么它在功能上等同于上述实现,并且将其放置在owin管道中是过度杀伤力的?

如果需要额外的设置,我想这种方法的另一个用途是dbContext的单个初始化点。


DbContext的设计是轻量级的,因此在每次需要新实例时创建一个新实例没有太大的成本。主要成本是重新创建连接和垃圾收集您正在创建的所有实例。

注意,如果在dbset上使用Find()方法,它将缓存结果,因此下次您请求它时,它不需要转到数据库。如果重新使用同一个上下文,可以利用该缓存,但如果创建新上下文,则会丢失缓存。

如果您将DbContext存储在控制器的实例成员中,那么它将仅用于一个请求,因为将为每个请求创建控制器的新实例。只要确保你不把它放在一个静态的成员-我希望你会得到各种各样的比赛条件,如果你这样做。


使用EFDB上下文的主要方法很简单:连接到DB上下文,获取数据并忽略这个DB上下文对象。ef上下文是IDisposable的,并在释放后关闭连接(不要忘记使用())。这意味着,当应用程序需要数据库连接时,可以在应用程序的任何位置创建EF数据上下文。如果控制器操作正在使用DB,则可以在其内部创建新的DB上下文。一切都取决于应用程序的体系结构。如果您确定,对您的应用程序的所有请求都需要许多DB操作,我认为您的解决方案(每个OWIN上下文都有DB上下文)是有用的。