我应该把实体框架作为一个非托管资源? [英] Should I Treat Entity Framework as an Unmanaged Resource?

查看:159
本文介绍了我应该把实体框架作为一个非托管资源?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我与使用在其构造为EF引用的类工作。

I am working with a class that uses a reference to EF in its constructor.

我已实施的IDisposable ,但我不知道我是否需要析构函数,因为我不能确定我可以归类为EF非托管资源。

I have implemented IDisposable, but I'm not sure if I need a destructor because I'm not certain I can classify EF as an unmanaged resource.

如果EF是一个管理的资源,那么我不需要析构函数,所以我认为这是一个适当的例子:

If EF is a managed resource, then I don't need a destructor, so I think this is a proper example:

public ExampleClass : IDisposable
{
    public ExampleClass(string connectionStringName, ILogger log)
    {
        //...
        Db = new Entities(connectionStringName);
    }

    private bool _isDisposed;

    public void Dispose()
    {
        if (_isDisposed) return;

        Db.Dispose();

        _isDisposed= true;
    }
}

如果EF未被托管,然后我会一起去这样的:

If EF is unmanaged, then I'll go with this:

public ExampleClass : IDisposable
{
    public ExampleClass(string connectionStringName, ILogger log)
    {
        //...
        Db = new Entities(connectionStringName);
    }

    public void Dispose()
    {
        Dispose(true);
    }

    ~ExampleClass()
    {
        Dispose(false);
    }

    private bool _isDisposed;

    protected virtual void Dispose(bool disposing)
    {
        if (_isDisposed) return;

        // Dispose of managed resources
        if (disposing)
        {
            // Dispose of managed resources; assumption here that EF is unmanaged.
        }
        // Dispose of unmanaged resources
        Db.Dispose();

        _isDisposed = true;
        //freed, so no destructor necessary.
        GC.SuppressFinalize(this);

    }
}



哪一个呢?

Which one is it?

推荐答案

您绝不会想使用在这种情况下终结(析构函数)。

You would never want to use a finalizer (destructor) in this case.

无论的DbContext 包含非托管资源或没有,甚至它是否负责任地释放这些非托管资源与否,是不是与您无关,是否可以尝试调用 DbContext.Dispose()从终结。

Whether DbContext contains unmanaged resources or not, and even whether it responsibly frees those unmanaged resources or not, is not relevant to whether you can try to invoke DbContext.Dispose() from a finalizer.

事实是,你有一个管理对象(其中的一个实例任何时候的DbContext 是),它的从不安全试图调用该实例上的任何方法。其原因是,由当时的终结器被调用时,的DbContext 对象可能已经被GC回收并不再存在。如果发生这种情况,你会得到一个的NullReferenceException试图打电话的时候, Db.Dispose()。或者,如果你是幸运的,而分贝仍是活着,异常也可以从在 DbContext.Dispose()抛出如果方法有上,至今已完成,并收集其他对象的依赖

The fact is that, any time you have a managed object (which an instance of DbContext is), it is never safe to attempt to invoke any method on that instance. The reason is that, by the time the finalizer is invoked, the DbContext object may have already been GC-collected and no longer exist. If that were to happen, you would get a NullReferenceException when attempting to call Db.Dispose(). Or, if you're lucky, and Db is still "alive", the exception can also be thrown from within the DbContext.Dispose() method if it has dependencies on other objects that have since been finalized and collected.

由于此的Dispose模式MSDN文章说

x无关访问的终结代码路径的终结对象,因为有显著风险,他们将已经敲定。

X DO NOT access any finalizable objects in the finalizer code path, because there is significant risk that they will have already been finalized.

例如,有另一个终结对象b的引用不能可靠地使用A的终结b,反之亦然终结对象的。终结被称为随机顺序(简称关键终止弱排序担保)。

For example, a finalizable object A that has a reference to another finalizable object B cannot reliably use B in A’s finalizer, or vice versa. Finalizers are called in a random order (short of a weak ordering guarantee for critical finalization).

另外,还要注意从埃里克利珀的下面当你知道一切是错误的,一部分2

Also, note the following from Eric Lippert's When everything you know is wrong, part two:

误区二:终结运行在可预知的顺序

假设我们有对象的树,所有的终结,和所有的终结队列中。 。不要求任何该树从根到叶敲定,从叶到根,或任何其他命令

Suppose we have a tree of objects, all finalizable, and all on the finalizer queue. There is no requirement whatsoever that the tree be finalized from the root to the leaves, from the leaves to the root, or any other order.

神话:一个对象正在确定可以安全地访问另一个对象。

这个神话直接从以前的遵循。如果你有对象的树,你正在最后确定的根,那么孩子还活着 - 因为根本是活的,因为它是终结队列,所以孩子们有一个生活参考 - 但孩子们可能已经已经定稿,并在没有特别好的状态,有自己的方法或访问的数据。

This myth follows directly from the previous. If you have a tree of objects and you are finalizing the root, then the children are still alive — because the root is alive, because it is on the finalization queue, and so the children have a living reference — but the children may have already been finalized, and are in no particularly good state to have their methods or data accessed.

别的东西来考虑:你有什么处置?是您的关心确保数据库连接及时关闭?如果是这样,那么你会感兴趣的是什么有 EF文件说这一点:


Something else to consider: what are you trying to dispose? Is your concern making sure that database connections are closed in a timely fashion? If so, then you'll be interested in what the EF documentation has to say about this:

默认情况下,上下文管理到数据库的连接。上下文打开,并根据需要关闭连接。例如,上下文打开一个连接执行查询,然后关闭时,所有的结果集已被处理的连接。

By default, the context manages connections to the database. The context opens and closes connections as needed. For example, the context opens a connection to execute a query, and then closes the connection when all the result sets have been processed.

这意味着,默认情况下,连接不需要 DbContext.Dispose()被称为及时关闭。作为查询执行它们被打开和关闭(从连接池)。因此,尽管它仍然是一个很不错的主意,以确保您随时来电 DbContext.Dispose()明确,是非常有用的知道,如果你不这样做,还是算了出于某种原因,默认情况下,这不会导致某种联系泄漏。

What this means is that, by default, connections don't need DbContext.Dispose() to be called to be closed in a timely fashion. They are opened and closed (from a connection pool) as queries are executed. So, though it's still a very good idea to make sure you always call DbContext.Dispose() explicitly, it's useful to know that, if you don't do it or forget for some reason, by default, this is not causing some kind of connection leak.

最后,最后一件事你可能要记住,是你贴一个没有终结,因为你实例化的DbContext 另一个类的构造函数中,它实际上是代码可能是 DbContext.Dispose()方法不会总是被调用。这是很好的了解这个特殊的情况下,这样你就不会与你的裤子抓住了。

And finally, one last thing you may want to keep in mind, is that with the code you posted that doesn't have the finalizer, because you instantiate the DbContext inside the constructor of another class, it is actually possible that the DbContext.Dispose() method won't always get called. It's good to be aware of this special case so you are not caught with your pants down.

例如,假设我曾经调整你的代码非常轻微,允许例外被抛出的之后在构造函数中实例化的DbContext 行:

For instance, suppose I adjust your code ever so slightly to allow for an exception to be thrown after the line in the constructor that instantiates the DbContext:

public ExampleClass : IDisposable
{
    public ExampleClass(string connectionStringName, ILogger log)
    {
        //...
        Db = new Entities(connectionStringName);

        // let's pretend I have some code that can throw an exception here.
        throw new Exception("something went wrong AFTER constructing Db");
    }

    private bool _isDisposed;

    public void Dispose()
    {
        if (_isDisposed) return;

        Db.Dispose();

        _isDisposed= true;
    }
}

和假设你的类使用这样的:

And let's say your class is used like this:

using (var example = new ExampleClass("connString", log))
{
    // ...
}

尽管这似乎是一种绝对安全的,干净的设计,因为一个例外是 ExampleClass中的构造函数中抛出的之后的新实例的DbContext 已经创建, ExampleClass.Dispose()永远不会被调用,并推而广之, DbContext.Dispose()决不会在新创建的实例或者调用

Even though this appears to be a perfectly safe and clean design, because an exception is thrown inside the constructor of ExampleClass after a new instance of DbContext has already been created, ExampleClass.Dispose() is never invoked, and by extension, DbContext.Dispose() is never invoked either on the newly created instance.

您可以阅读更多关于这种不幸局面的这里

You can read more about this unfortunate situation here.

要确保的DbContext 的Dispose()方法总是被调用,不管里面有什么发生在 ExampleClass中的构造函数,你将不得不修改 ExampleClass中类是这样的:

To ensure that the DbContext's Dispose() method is always invoked, no matter what happens inside the ExampleClass constructor, you would have to modify the ExampleClass class to something like this:

public ExampleClass : IDisposable
{
    public ExampleClass(string connectionStringName, ILogger log)
    {
        bool ok = false;
        try 
        {
            //...
            Db = new Entities(connectionStringName);

            // let's pretend I have some code that can throw an exception here.
            throw new Exception("something went wrong AFTER constructing Db");

            ok = true;
        }
        finally
        {
            if (!ok)
            {
                if (Db != null)
                {
                    Db.Dispose();
                }
            }
        }
    }

    private bool _isDisposed;

    public void Dispose()
    {
        if (_isDisposed) return;

        Db.Dispose();

        _isDisposed= true;
    }
}



不过上面是真的只有在构造一个问题不仅仅是创建一个的DbContext

这篇关于我应该把实体框架作为一个非托管资源?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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