微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c# – 为什么需要在客户端项目中引用EntityFramework.dll以使DbContext IDisposable?

创建一个具有Entity Framework模型和对象上下文的类库.然后向解决方添加新的控制台应用程序.从控制台应用程序,引用具有您的模型的项目.

现在在控制台应用中输入:

static void Main(string[] args)
{
    using (var context = new ExperimentalDbContext())
    {

    }
    Console.ReadKey();
}

在构建时,您将收到报告错误

The type ‘System.Data.Entity.DbContext’ is defined in an assembly that
is not referenced. You must add a reference to assembly
EntityFramework…yada yada yada…

现在,我在过去几年中已经多次这样做了,但每当我收到此错误时,我再一次无助地在互联网上搜索我当时忘记的解决方案.

解决此问题需要您在ConsoleClient项目中安装EntityFramework NuGet包.

所以,我的问题不在于修复是什么,而是为什么?因为它没有任何意义!

仅仅为了完整起见,我使用的是实体框架的v6.1.3.但是,多年来我在早期版本中也多次看到过这个错误.

更新

看来只有当您使用要在Idisposables上调用dispose的using代码块时才会出现问题.

要测试该假设,请使用以下代码创建一个控制台应用程序,该应用程序在同一解决方案中引用ClassLibrary1,该解决方案在同一解决方案中引用ClassLibrary2:

using ClassLibrary1;
using System;

namespace TestHypothesis1
{
    class Program
    {
        // Testing the hypothesis presented in this answer: https://stackoverflow.com/a/38130945/303685
        // This seems to be the behavior with just (or may be even others I haven't tested for)
        // Idisposable.
        // anotherFoo instance is created just fine,but the moment I uncomment
        // the using statement code,it shrieks.
        static void Main(string[] args)
        {
            //using (var foo = new Foo())
            //{
            //    foo.Gar = "Gar";

            //    Console.WriteLine(foo.Gar);
            //}

            var anotherFoo = new Foo() { Gar = "Another gar" };
            Console.WriteLine(anotherFoo.Gar);

            Console.ReadKey();
        }
    }
}


using ClassLibrary2;
using System;

namespace ClassLibrary1
{
    public class Foo: Bar,Idisposable
    {
        public string Gar { get; set; }

        public void dispose()
        {
            throw new NotImplementedException();
        }
    }
}


namespace ClassLibrary2
{
    public class Bar
    {
        public string Name { get; set; }
    }
}

并且您将观察到编译器仅对第一个Foo的实例化而不是第二个实例的实例化抱怨缺少引用.

但奇怪的是,在第一个EntityFramework示例中,如果从控制台应用程序中删除了对EntityFramework.dll的引用并将Main中的代码更改为此,它仍会抱怨缺少引用.

static void Main(string[] args)
{
    var context = new ExperimentalDbContext();
    Console.ReadKey();
    context.dispose();
}

另外,如果你注释掉上面代码片段的最后一行context.dispose()的调用,代码仍然可以正常工作,即使它抛出InvalidOperationException,但我猜测,这是由于上下文的竞争条件在其迭代器完成其MoveNext调用之前被释放.

static void Main(string[] args)
{
    var context = new ExperimentalDbContext();
    Console.ReadKey();
    // context.dispose();
}

所以,新的附加问题现在变成:

实现using语句的方式是什么让编译器在链接引用中停止了?

最初的问题也仍然存在.

又一次更新

现在看来问题可能会进一步归结为对Idisposable.dispose方法调用,因此问题不在于使用using语句. using语句似乎是一个无辜的保证,dispose将被调用,而不是其他任何东西.

因此,在上面的Foo示例中,如果在最后插入对anotherFoo.dispose的调用,编译器会再次开始抱怨.像这样:

using ClassLibrary1;
using System;

namespace TestHypothesis1
{
    class Program
    {
        // Testing the hypothesis presented in this answer: https://stackoverflow.com/a/38130945/303685
        // This seems to be the behavior with just (or may be even others I haven't tested for)
        // Idisposable.
        // anotherFoo instance is created just fine,it shrieks.

        // Final update:
        // The trigger for the error seems to be the call to the dispose method and not
        // particularly the implementation of the using statement,which apparently,simply
        // ensures that dispose is called,as is also well-kNown and documented.
        static void Main(string[] args)
        {
            //using (var foo = new Foo())
            //{
            //    foo.Gar = "Gar";

            //    Console.WriteLine(foo.Gar);
            //}

            var anotherFoo = new Foo() { Gar = "Another gar" };
            Console.WriteLine(anotherFoo.Gar);

            anotherFoo.dispose();

            Console.ReadKey();
        }
    }
}

那么,最后一个问题,总结如下:

为什么调用dispose会阻止编译器链接汇编引用?

我想我们现在正在某个地方.

解决方法

原始答案

我不认为它特定于DbContext,但或多或​​少是因为类库中引用的依赖DLL不会转移到控制台应用程序.因此,在构建时,编译器只知道控制台应用程序中的引用,而不知道EntityFramework的链接引用.它抱怨的唯一原因是因为编译器使用using语句运行检查以确保该类具有Idisposable,并且它唯一可以知道的是它是否解析了EntityFramework库中的引用.

更新

事实证明我仍然认为这是对的.如果在您的示例中,您忘记了Idisposable并且只是尝试在控制台应用程序中使用Bar类的属性Name,您会发现它得到一个它不知道该属性的异常,因为它是未引用的部件.

未引用的程序集错误示例:

(inside Main)
Console.WriteLine(anotherFoo.Name);

为了它的价值,你实际上可以引用具有嵌套引用的库,并且永远不会在应用程序中包含那些嵌套引用,只要调用代码实际上永远不会到达引用或需要嵌套库的代码路径.这可能是容易出错的源,特别是对于部署/发布方案.想象一下,您的发布不包含应用程序所需的所有库,但只需要很少调用需要深层嵌套库的代码路径.然后有一天,你接到一个电话,说“应用程序坏了!”一个人立即倾向于说“但没有改变!我们自上次以来没有部署过!”这是在测试,QA,部署后等方面获得良好代码覆盖率的重要原因之一.

原文地址:https://www.jb51.cc/csharp/99245.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐