2013-02-10 38 views
0

我一直在努力弄清楚为什么这段代码在foreach循环之前放置dbcontext。任何线索将不胜感激。谢谢!为什么在foreach循环之前放置dbcontext

[TestMethod] 
    public void CreatePostAddComment() 
    { 
     IQueryable<Post> thePost; 
     using (var _context = new BlogRepository()) 
     { 
      _context.AddPost(GetTestPost()); 
      var retrivePost = _context.GetPostByName("TestPost1"); 
      thePost = retrivePost; 
     } 

     foreach (var post in thePost) 
     { 
      using (var _dbContext = new BlogRepository()) 
      { 
       _dbContext.AddComment(GetTestComment(post)); 
      } 

     } 
    } 
+1

使用在其块的末尾放置上下文。 – 2013-02-10 18:48:57

+0

我知道了,但是IQueryable 应该还是在foreach范围之内? – 2013-02-10 18:50:06

+0

不可以。仅仅因为您已声明变量超出其范围之外,处置不会延迟。 – 2013-02-10 18:58:12

回答

2

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(); 
    } 
} 
+0

感谢您的信息。从我的例子中唯一不同的是,GetPostByName和GetTestComment在存储库中的相应方法中调用了保存更改。 – 2013-02-10 19:05:38

+0

我会高度建议不要让SaveChanges在像GetTestPost和GetPostByName这样的域代码内调用。它将永远将你与EntityFramework联系起来。您的域代码应该与存储库的实现无关。如果要测试域代码,则可以将存储库更改为列表。 另外,实施存储库模式。 – Aron 2013-02-10 19:14:09

相关问题