【问题标题】:'DbContext has been disposed error' on Multiple Calls多次调用时出现“DbContext 已处理错误”
【发布时间】:2017-02-04 00:44:37
【问题描述】:

我设置了一个 API,它有一个简单的 getCustomers() 方法。端点在第一次调用时返回数据,但在第二次调用时返回错误。

错误:操作无法完成,因为 DbContext 已被释放

错误是在我的CustomerServicereturn db.Customers...内引起的

问题:为什么这在第一次调用时有效,但在第二次调用时失败。如何解决?

GitHub Repo 可以在这里找到: https://github.com/ChaseHardin/MyBookStore

下面是代码的演练:

控制器:

[RoutePrefix("api/customers")]
public class CustomerController : ApiController
{
    private readonly CustomerService _service = new CustomerService();

    [HttpGet, Route("")]
    public virtual IHttpActionResult Get()
    {
        var customers = _service.GetCustomers();
        return Ok(new {customers});
    }
}

客户服务:

public class CustomerService : BaseService
{
    public List<CustomerViewModel> GetCustomers()
    {
        using (var db = Application.GetDatabaseInstance())
        {
            return db.Customers.Select(AutoMapper.Mapper.Map<CustomerViewModel>).ToList();
        }
    }
}

基础服务

public class BaseService
{
    public BaseService()
    {
        AutoMapperConfiguration();
    }

    public void AutoMapperConfiguration()
    {
        Assembly.GetExecutingAssembly()
                 .GetTypes()
                 .Where(x => x.IsClass && x.Namespace == "MyBookStore.Business.ViewModels")
                 .ForEach(x => System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(x.TypeHandle));

        AutoMapper.Mapper.CreateMap<bool, short?>().ConvertUsing(x => x ? (short)1 : (short)0);
        AutoMapper.Mapper.CreateMap<short, bool>().ConvertUsing(x => x == 1);

        AutoMapper.Mapper.CreateMap<bool, int?>().ConvertUsing(x => x ? 1 : 0);
        AutoMapper.Mapper.CreateMap<int?, bool>().ConvertUsing(x => x.HasValue && x.Value == 1);

        AutoMapper.Mapper.CreateMap<short, int>().ConvertUsing(x => (int)x);
        AutoMapper.Mapper.CreateMap<int, int?>().ConvertUsing(x => x);
    }
}

客户视图模型

public class CustomerViewModel
{
    static CustomerViewModel()
    {
        AutoMapper.Mapper.CreateMap<Customer, CustomerViewModel>().ReverseMap();
    }

    public Guid CustomerId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

上下文设置:

public class Application
{
    private static readonly MyBookStoreEntity Context = new MyBookStoreEntity();

    public static MyBookStoreEntity GetDatabaseInstance()
    {
        return Context;
    }
}

【问题讨论】:

  • 看起来你的上下文是一个单例,你在使用它后将其丢弃。
  • 您在 using 语句中使用静态上下文,因此使用一次,然后将其处理掉。永远不要使用静态上下文!
  • 静态数据库上下文是一个著名的坏主意。您已经找到了原因之一。
  • 好的,所以我删除了静态数据库上下文并实例化了我的Application。但是,我仍然收到那个 DbContext 错误。还有其他想法吗?
  • 显示您的代码现在的样子。

标签: c# entity-framework automapper


【解决方案1】:

当您使用using 块时:

using (var db = Application.GetDatabaseInstance())

正在“使用”的对象将被放置在块的末尾。 (using 基本上是 try/finally 的语法简写,其中 finally 块在对象上调用 .Dispose()。)

而你“使用”的是这个值:

private static readonly MyBookStoreEntity Context = new MyBookStoreEntity();

这个值是static,所以每次调用它都是MyBookStoreEntity的同一个实例。但是当你第一次调用它时,你.Dispose()它。因此,任何后续调用都将在已处置的对象上。

基本上,您已经发现了static 数据库上下文是一个非常 坏主意的原因之一。你仍然可以像你一样将你的数据库上下文封装到一个方法中,但是让方法每次都返回一个新实例:

public static MyBookStoreEntity GetDatabaseInstance()
{
    return new MyBookStoreEntity();
}

或者,如果该方法此时并没有真正提供任何好处,那么只需在您需要的地方创建上下文:

using (var db = new MyBookStoreEntity())

创建数据库上下文并不是一项特别繁重的操作。但是,当您不使用它们时,请保留它们。 (并且在不同的操作之间共享它们充满了危险。)一个好的经验法则是离散地定义您需要为给定的应用程序操作执行的数据库操作,并在代码中创建/使用/处置您的数据库连接尽可能阻止这些操作。

【讨论】:

    猜你喜欢
    • 2017-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多