0

我一直在努力弄清楚为什么这段代码会在 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));
            }

        }
    }
4

1 回答 1

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));
        }

    }
}

但是,您的代码存在几个关键问题,其中只有第一个是 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();
    }
}
于 2013-02-10T19:02:13.657 回答