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));
}
}
}
但是也有你的代码的几个关键问题,只有第一个是语境处理完毕异常。
关于上下文被处理的第一个问题是因为只有在枚举实际的IQueryable(在本例中为foreach)时才会调用EF查询。换句话说,IQueryable没有做任何工作,而且很懒惰。当foreach实际上需要IQueryable去获取它的信息时,上下文已经被处理了。
其次,你不能在你刚刚得到的姿势上工作,因为你正在使用另一个上下文。 EF会抱怨帖子对象仍然附着在旧的上下文中。这个问题将突出更一般的模式。只要你的“工作单位”,你应该保持你的背景。一般来说,在调用DbContext.SaveChanges()之后进行处理。
这导致我到你的第三个错误。你没有调用DbContext.SaveChanges()。这段代码没有什么会发生。您不会写入数据库,EF验证不会运行,除非内存即将超出范围,否则不会发生任何事情。
最后你的测试方法产生的副作用(假设它会成功保存)。这将导致痛苦点进一步下降。解决此问题的一种方法是在测试之前开始事务,并在测试之后回滚。
我知道MbUnit会为你做事务逻辑,如果你想沿着这条路走下去的话。
所以总结起来,这是我会做什么......假设我理解你正在试图achieve-
从文体点我恨CRUD方法是什么。像GetPostByName这样的方法,当你有Linq的时候。我使用它的问题包括更多的代码维护(如果您更改为nHibernate,则需要重新实现GetPostByName)。其次,接下来你会发现你需要一个GetPostByDescript,然后一个GetPostById,然后一个GetPostByDescriptionOrName ...等等等等。带有像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();
}
}
使用在其块的末尾放置上下文。 – 2013-02-10 18:48:57
我知道了,但是IQueryable应该还是在foreach范围之内? –
2013-02-10 18:50:06
不可以。仅仅因为您已声明变量超出其范围之外,处置不会延迟。 – 2013-02-10 18:58:12