using 语句实际上是语法糖,它相当于:-
[TestMethod]
public void CreatePostAddComment()
{
IQueryable<Post> thePost;
{
var _context = new BlogRepository();
_context.AddPost(GetTestPost());
var retrivePost = _context.GetPostByName("TestPost1");
thePost = retrivePost;
_context.Dispose();
//Note, using is much better, because Dipose is called
//even if there is an exception.
}
foreach (var post in thePost)
{
using (var _dbContext = new BlogRepository())
{
_dbContext.AddComment(GetTestComment(post));
}
}
}
但是,您的代码存在几个关键问题,其中只有第一个是 Context Disposed Exception。
您关于正在处理的上下文的第一个问题是因为仅当您枚举实际的 IQueryable 时才会调用 EF 查询,在这种情况下,是在 foreach 中。换句话说,IQueryable 没有做任何工作并且是懒惰的。当 foreach 实际上需要 IQueryable 去获取它的信息时,此时上下文已经被释放。
其次,您不能对刚刚获得的姿势进行处理,因为您使用的是另一个上下文。EF 会抱怨 post 对象仍附加到旧上下文。这个问题将突出一个更普遍的模式。只要您的“工作单元”,您就应该保留您的上下文。一般来说,您在调用 DbContext.SaveChanges() 后进行处理。
这导致我发现你的第三个错误。您没有调用 DbContext.SaveChanges()。这段代码不会发生任何事情。您不会写入数据库,不会运行 EF 验证,除了即将超出范围的内存之外,什么都不会发生。
最后,您的测试方法正在产生副作用(假设它会成功保存)。这将导致进一步的痛点。解决此问题的一种方法是在测试之前开始事务,并在测试之后回滚。
我知道如果你想走这条路,MbUnit 会为你做交易逻辑。
总而言之,这就是我会做的……假设我了解您要实现的目标-
从风格的角度来看,我讨厌 CRUD 方法。像 GetPostByName 这样的方法,当你有 Linq 时。我遇到的问题包括需要维护更多代码(如果您切换到 nHibernate,则需要重新实现 GetPostByName)。其次,您接下来会发现您需要一个 GetPostByDescript,然后是 GetPostById,然后是 GetPostByDescriptionOrName ......等等......
PS。使用像 ThePost 这样的名称,我假设您是在单个实例之后....
[Rollback]
[TestMethod]
public void CreatePostAddComment()
{
using(var _context = new BlogRepository())
{
_context.AddPost(GetTestPost());
_context.SaveChanges();
var thePost = _context.Posts.First(x => x.Name =="TestPost1");
_dbContext.AddComment(GetTestComment(post));
_context.SaveChanges();
}
}