我是实体框架的新手,我正在编写一个基于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; }
}
还有更多的DbSets。我应该为每个人创建一个单独的上下文吗?
我的一个基本控制器:
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;
}
}
我在本地运行网站时似乎没有看到这些错误,虽然我们有两个人在发布时遇到它,所以问题可能来自多个用户?
答案 0 :(得分:9)
Chris,我注意到你的控制器中你正在使用控制器类中的所有方法共享你的db上下文。
这通常不是实体框架中的最佳做法(请参阅: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;
}
}
}
我建议您尝试上述更改,看看您的行为是否更稳定。
答案 1 :(得分:1)
由于我不知道您的网页如何使用方法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及以上。