对象实例已被释放,不能再用于需要连接的操作
本文关键字:用于 连接 操作 不能 实例 释放 对象 | 更新日期: 2023-09-27 18:32:50
我使用 EF6。在我的BL层中,我有以下静态类,使用我的上下文,它实现了DBContext:
public static class AppEnvironment
{
public static IUser CurrentUser { get; set; }
private static IKernel AppKernel { get; set; }
public static void InjectDependencies(params NinjectModule[] contextNinjectModule)
{
AppKernel = new StandardKernel(contextNinjectModule);
}
public static void Authorize(string login, string password)
{
using (var context = AppKernel.Get<ICaseContext>())
{
IUser userToBeAuthorized = context.GetAll<User>().FirstOrDefault(u => u.Login == login);
if (userToBeAuthorized != null && User.GetMD5Hash(password) == userToBeAuthorized.PasswordHash)
{
AppEnvironment.CurrentUser = userToBeAuthorized;
context.Insert(
LogRecord.CreateLogRecord(
userToBeAuthorized,
"Авторизация (успешно)",
LogAction.Read));
}
}
}
public static ICollection<CaseEntityType> GetCaseListTiny<CaseEntityType>(string queryComment) where CaseEntityType : CaseEntityBase
{
using (var context = AppKernel.Get<ICaseContext>())
{
var grantedCaseTypesIDs = AppEnvironment.CurrentUser.CaseTypesGranted.Select(casetype => casetype.ID).ToList();
var cases = context.GetAllIncluding<TaskEntityType>(AppEnvironment.CurrentUser, queryComment, LogAction.Read, t => t.CaseType
).Where(t => grantedTaskTypesIDs.Contains(t.CaseType.ID)).ToList();
return cases;
}
}
}
在我的 UI 层中,我尝试像这样使用 smth:
class Program
{
static void Main(string[] args)
{
AppEnvironment.InjectDependencies(new RealContextNinjectModule());
AppEnvironment.Authorize("UserName", "Password");
var caseList = AppEnvironment.GetCaseListTiny<RegularCase>("Get a list");
foreach (var item in caseList)
{
Console.WriteLine(item.Name);
}
}
}
但它抛出了 ObjectContextDisposedException。谁能解释一下处理 EF6 上下文类的正确方法是什么?我应该如何在我的 BLL 或 UIL 中使用它?为什么不允许我在处理一次上下文类后再次使用它?我读过很多类似的问题,但每个人都只说急切/懒惰加载。
"每个人都只说急切/懒惰加载"的原因是因为这就是正在发生的事情。事件的顺序为:
var caseList = AppEnvironment.GetCaseListTiny<RegularCase>("Get a list");
然后,GetCaseTinyList 调用 AppKernel.Get,它将上下文返回到包装在 using 块中的本地 var 上下文中。在块中,它通过对上下文发出调用来创建集合。它不访问该列表,因此集合实际上并未填充;在访问集合之前,不会运行任何 SQL。这是懒惰的演讲。
在 using 块的末尾,它会释放上下文。这将关闭数据库连接,并将上下文对象标记为已释放,因此不可用。
GetCaseTinyList 返回,将未填充的集合传递回去。
最后,对返回的集合运行 foreach 。在第一次访问时,EF 集合尝试针对上下文运行 GetCaseTinyList 的 SQL。可悲的是,上下文已被处理(您确实告诉它处理它,因此它确实如此(。这使得系统完全按照应有的方式抛出您遇到的错误。
解决此问题的一种方法是更改GetCaseTinyCollection以访问集合;如下所示:
public static ICollection<CaseEntityType> GetCaseListTiny<CaseEntityType>(string queryComment) where CaseEntityType : CaseEntityBase
{
using (var context = AppKernel.Get<ICaseContext>())
{
var grantedCaseTypesIDs = AppEnvironment.CurrentUser.CaseTypesGranted.Select(casetype => casetype.ID).ToList();
var cases = context.GetAllIncluding<TaskEntityType>(AppEnvironment.CurrentUser, queryComment, LogAction.Read, t => t.CaseType
).Where(t => grantedTaskTypesIDs.Contains(t.CaseType.ID)).ToList();
int count = cases.Count(); // or Count<T>();
return cases;
}
}
这将强制在释放上下文之前填充集合。但是,它可能还有进一步的缺点:如果集合中的实体依次具有其他对象的集合,那么在访问时,它将尝试填充这些子集合,然后您又回到了现在的位置。
另一种方法是不使用使用/释放模式。但是在某些时候,您将不得不清理上下文,因此您必须考虑如何做到这一点。
此外,在插入/更新 EF 实体时,保留用于读取数据的上下文要容易得多。如果您不这样做,则必须将更新的实体转移到听起来很痛苦的新上下文中(我从未这样做过(。
基本上,您需要重新考虑管理数据库上下文的策略。