【问题标题】:Database connection errors on EFEF 上的数据库连接错误
【发布时间】:2014-06-17 20:55:22
【问题描述】:

我对实体框架非常陌生,我正在编写的基于 Web api 的站点(连接到 mssql)有问题。我不断收到看似随机的错误(大部分似乎与数据库相关)。这些错误最常发生在网站首次发布时,但有时也会发生在距离上次发布数小时后。错误选择:

  • 操作无效。连接已关闭。
  • 已经有一个打开的 DataReader 与此命令关联,必须先关闭。
  • 连接未关闭。连接的当前状态为正在连接。
  • 创建模型时无法查看上下文
  • 基础提供程序无法打开

我的上下文如下所示:

public class Context : DbContext
{

    public Context() : base("name=DefaultConnection")
    {
    }

    public override int SaveChanges()
    {
        DateTime now = DateTime.Now;
        foreach (ObjectStateEntry entry in (this as IObjectContextAdapter).ObjectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified))
        {
            if (!entry.IsRelationship)
            {
                IHasUpdated updated = entry.Entity as IHasUpdated;
                if (updated != null)
                    updated.updated = now;
            }
        }
        return base.SaveChanges();
    }

    public DbSet<Branch> Branches { get; set; }
    public DbSet<Company> Companies { get; set; }
    public DbSet<User> Users { get; set; }
    public DbSet<UsefulLink> UsefulLinks { get; set; }
}

还有比这更多的 DbSet。我应该为每个创建一个单独的上下文吗?

我的一个基本控制器:

 public class UsefulLinksController : ApiController
 {
    private Context db = new Context();

    [ResponseType(typeof(UsefulLinksWrapper))]
    public IHttpActionResult GetUsefulLinks([FromUri]UsefulLinkParams prams)
    {   
        UsefulLinksWrapper wrapper = new UsefulLinksWrapper();
        Meta meta = new Meta();
        IQueryable<UsefulLink> query = db.UsefulLinks;

    if (prams.sortBy == null)
        {
            prams.sortBy = "ID";
        }

        // Paging
        query = query.OrderBy(prams.sortBy + " " + prams.sortDirection).Skip(prams.offset - 1).Take(prams.limit);

        List<UsefulLink> data = query.ToList();

        meta.totalCount = query.Count();
        meta.offset = 1;
        meta.limit = prams.limit;
        wrapper.meta = meta;
        wrapper.data = data;

        return Ok(wrapper);

    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            db.Dispose();
        }
        base.Dispose(disposing);
    }

    private bool UsefulLinkExists(int id)
    {
        return db.UsefulLinks.Count(e => e.ID == id) > 0;
    }
}

当我在本地运行该网站时,我似乎没有看到这些错误,尽管我们有两个人在它发布时点击了它,所以问题可能源于多个用户?

【问题讨论】:

  • 数据库上下文的生命周期是什么?它应该是每个请求。
  • 在连接字符串中设置 MultipleActiveResultSets=True 并确保没有单个上下文实例被多个线程访问(如果您在控制器之间共享上下文实例可能会发生这种情况)。
  • @prnjanuario 我不知道!我怎么知道。
  • @GertArnold 不幸的是,添加连接字符串是我尝试的第一件事,它似乎没有任何区别。我的情况和你的情况不同,所以我会确保这不是问题!
  • 您应该尽量缩小您的问题范围。尝试找到仍然重现问题的最小代码段。理想情况下,它是如此之小,您可以将其完全张贴在这里 - 如果您在缩小代码的过程中没有找到根本原因。示例:如果您只有一个 DbSet,是否仍然会发生这种情况?如果您使用来自命令行项目而不是 MVC 的实体,会发生这种情况吗? ...

标签: c# entity-framework asp.net-web-api


【解决方案1】:

克里斯,我注意到在您的控制器中,您正在与控制器类中的所有方法共享您的数据库上下文。

这通常不是实体框架中的最佳实践(请参阅:EntityFramework 4 ObjectContext Lifetime)。您应该尽可能简短地保持上下文活跃。让上下文保持活动状态以在多个方法之间共享可能会导致您上面列出的许多错误。

我建议尝试实例化上下文的新实例,而不是在使用它的任何地方并快速处理它。

这通常会导致更稳定的行为。

所以下面:

class SomeClass
{
   private context = new Context(); //sharing your context with all methods
   public someMethod()
   {
      context.doSomething;
   }

   public someMethod2()
   {
      context.doSomething;
   }
}

应该变成:

class SomeClass
{

   public someMethod()
   {
      Context context = new Context(); //now your context is declared and disposed of within each method
      context.doSomething;
   }

   public someMethod2()
   {
      Context context = new Context(); //now your context is declared and disposed of within each method
      context.doSomething;
   }
}

或者更好的是,您可以使用 using 构造来确保正确处理您的上下文:

class SomeClass
{
   public someMethod3()
   {
      using(Context context = new Context()) //now wrapping the context in a using to ensure it is disposed
      {
         context.doSomething;
      }
   }
}

我建议您尝试上述更改,看看您的行为是否变得更加稳定。

【讨论】:

  • 看起来真不错。我会试一试,然后回复你。如果可行,我将恢复我之前的赏金。
  • 嗨,克里斯。我看到您将此标记为答案。那么进展如何?
  • 控制器的实例是否在请求之间保持不变?
【解决方案2】:

由于我不知道您的页面如何使用UsefulLinksController 方法以及使用顺序,我想说UsefulLinkExists 可能是lazy loading 的罪魁祸首

延迟加载意味着延迟加载相关数据,直到您 具体要求

这可以解释为什么你的“阅读器”保持“开放”。

试试:

return db.UsefulLinks.ToList().Count(e => e.ID == id) > 0;

无论如何,您可以在上下文构造函数中默认禁用延迟加载,例如noted here

public MyEntitiesContext() : base("name=MyEntitiesContext", "MyEntitiesContext")
{
    this.ContextOptions.LazyLoadingEnabled = false;
    OnContextCreated();
}

据我所知,它适用于 EF4 及更高版本。

【讨论】:

  • 我不认为这里会发生延迟加载,因为在我的任何模型上都没有将链接属性设置为虚拟。我不想在项目中的任何地方延迟加载,因为它会在 json 序列化时给我们带来问题,我需要专门将其关闭吗?我在任何我想要链接实体的地方都使用包含。
  • @ChrisFoot 我不知道是否有任何方法可以通过模型设置等将其关闭,但我已经多次遇到这个问题,尽管在不同的情况下并且通常在做ToList()由于上述原因解决了这个问题。
  • 我使用链接上接受的答案中的代码全局禁用了延迟加载,但不幸的是它仍在发生。
  • 我现在也尝试了 ssmith 的解决方案,并确认延迟加载肯定在调试中被禁用,问题仍然存在
  • @ChrisFoot 是在读取或写入操作期间发生错误,还是两者兼而有之?
猜你喜欢
  • 2012-06-05
  • 2014-08-24
  • 2012-01-21
  • 1970-01-01
  • 1970-01-01
  • 2012-10-29
  • 1970-01-01
相关资源
最近更新 更多