由于方法调用导致嵌套的DbContext-实体框架 [英] Nested DbContext due to method calls - Entity Framework

查看:178
本文介绍了由于方法调用导致嵌套的DbContext-实体框架的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在以下情况下,由于方法调用而嵌套了两个DbContext:

In the following case where two DbContexts are nested due to method calls:

public void Method_A() {
    using (var db = new SomeDbContext()) {
        //...do some work here
        Method_B();
        //...do some more work here
    }
}

public void Method_B() {
    using (var db = new SomeDbContext()) {
        //...do some work
    }
}

问题:


  1. 此嵌套会引起任何问题吗? (并且正确的DbContext是否会在正确的时间处理?)

  1. Will this nesting cause any issues? (and will the correct DbContext be disposed at the correct time?)

此嵌套是否被认为是不好的做法,应该将Method_A重构为:

Is this nesting considered bad practice, should Method_A be refactored into:

public void Method_A() {
    using (var db = new SomeDbContext()) {
        //...do some work here
    }

    Method_B();

    using (var db = new SomeDbContext()) {
        //...do some more work here
    }
}


谢谢。

推荐答案

您的 DbContext 派生类实际上在这里为您管理了至少三件事:

Your DbContext derived class is actually managing at least three things for you here:


  • 描述您的数据库和实体模型的元数据

  • 基础数据库连接,以及

  • 使用上下文加载的实体的客户端缓存,用于更改跟踪,关系修正等。(请注意,尽管我称其为缓存是为了获得更好的词,但这通常是短暂的,仅用于支持EFs功能。它不能替代应用程序中的适当缓存。)

实体框架通常会缓存元数据(项目1)以便所有上下文实例(或至少所有使用相同连接字符串的实例)共享它。因此,这里不必担心。

Entity Framework generally caches the metadata (item 1) so that it is shared by all context instances (or, at least, all instances that use the same connection string). So here that gives you no cause for concern.

如其他注释所述,您的代码导致使用两个数据库连接。

As mentioned in other comments, your code results in using two database connections. This may or may not be a problem for you.

您还最终获得了两个客户端缓存(项目3)。如果您恰巧是从外部上下文中加载一个实体,然后再次从内部上下文中加载一个实体,则在内存中将有该实体的两个副本。这肯定会造成混乱,并可能导致细微的错误。这意味着,如果您不想使用共享上下文对象,那么您的选项2可能会比选项1更好。

You also end up with two client caches (item 3). If you happen to load an entity from the outer context, then again from the inner context, you will have two copies of it in memory. This would definitely be confusing, and could lead to subtle bugs. This means that, if you don't want to use shared context objects, then your option 2 would probably be better than option 1.

如果您使用的是交易,则需要进一步考虑。具有多个数据库连接可能会导致将事务提升为分布式事务,这可能不是您想要的。由于您没有提及数据库事务,因此我在这里不做进一步介绍。

If you are using transactions, there are further considerations. Having multiple database connections is likely to result in transactions being promoted to distributed transactions, which is probably not what you want. Since you didn't make any mention of db transactions, I won't go into this further here.

如果您只是为了避免在代码中传递 DbContext 对象而使用此模式,那么您可能会更好重构 MethodB 来接收上下文作为参数。有关应使用多长时间的上下文对象的问题反复出现。根据经验,可以为单个数据库操作或一系列 related 数据库操作创建新的上下文。 (例如,请参见此博客帖子此问题。)

If you are using this pattern simply to avoid passing DbContext objects around in your code, then you would probably be better off refactoring MethodB to receive the context as a parameter. The question of how long-lived context objects should be comes up repeatedly. As a rule of thumb, create a new context for a single database operation or for a series of related database operations. (See, for example this blog post and this question.)

(作为替代,您可以向接收现有连接的 DbContext 派生类中添加一个构造函数。然后,您可以在多个上下文之间共享相同的连接。

(As an alternative, you could add a constructor to your DbContext derived class that receives an existing connection. Then you could share the same connection between multiple contexts.)

一种有用的模式是编写自己的类,该类创建一个上下文对象并将其存储为私有字段或属性。然后,使您的类实现 IDisposable ,其 Dispose()方法将处理上下文对象。您的调用代码将消息通知您的类的一个实例,而根本不必担心上下文或连接。

One useful pattern is to write your own class that creates a context object and stores it as a private field or property. Then you make your class implement IDisposable and its Dispose() method disposes the context object. Your calling code news up an instance of your class, and doesn't have to worry about contexts or connections at all.

当您需要编写多线程代码时,这很有用。数据库连接不是线程安全的,因此您一次只能从一个线程访问一个连接(因此也只能访问一个EF上下文)。如果限制太严格,则需要多个连接(和上下文),每个线程一个。您可能会发现很有趣。

This can be useful when you need to write code that is multi-threaded. A database connection is not thread-safe, so you must only ever access a connection (and therefore an EF context) from one thread at a time. If that is too restrictive, you need multiple connections (and contexts), one per thread. You might find this interesting.

这篇关于由于方法调用导致嵌套的DbContext-实体框架的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆