我使用EF6。在我的BL-Layer中,我有以下静态类,使用我的上下文,它实现了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中使用它?为什么我不允许再次使用我的上下文类,在它被处置一次之后呢?我已经阅读了很多类似的问题,但每个人都说只有关于急切/懒惰加载的问题。
答案 0 :(得分:2)
&#34;每个人都只说关于渴望/延迟加载的问题&#34;是因为那就是发生了什么。事件的顺序是:
var caseList = AppEnvironment.GetCaseListTiny<RegularCase>("Get a list");
GetCaseTinyList然后调用AppKernel.Get,它将上下文返回到 using 块中包含的本地 var context 。在块中,它通过针对上下文发出调用来创建集合。它不访问该列表,因此实际上并未填充该集合;在访问集合之前不会运行SQL。这是懒惰的效果。
在使用块的末尾,它处理上下文。这将关闭数据库连接,并将上下文对象标记为已丢弃,因此无法使用。
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;
}
}
这将强制在处理上下文之前填充集合。然而,它可能还有其他缺点:如果集合中的实体反过来又收集了其他对象,那么当它们被访问时,它会尝试填充这些子集合,并且你会回到现在的位置。
另一种方法是不使用using / dispose模式。但在某些时候,你将不得不清理上下文,所以你必须考虑如何做到这一点。
此外,在插入/更新EF实体以保持您用于读取数据的上下文时,它会容易得多。如果你不需要将更新的实体转移到一个听起来很痛苦的新环境(我从未这样做过)。
基本上,您需要重新考虑管理数据库上下文的策略。