为什么dbcontext被放置在foreach循环之前 [英] Why is dbcontext disposed before the foreach loop

查看:52
本文介绍了为什么dbcontext被放置在foreach循环之前的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've been struggling trying to figure out why this code disposes dbcontext before the foreach loop. Any clues would be greatly appreciated. Thanks!

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

        }
    }

推荐答案

using语句实际上是语法糖,它等效于:-

The using statement is in fact syntactic sugar it is equivalent to : -

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

    }
}

但是,您的代码存在几个关键问题,只有第一个是上下文处理异常.

However there are several key problems with your code, only the first of which is the Context Disposed Exception.

关于被处理的上下文的第一个问题是,仅当在foreach枚举实际的IQueryable时(在这种情况下),才调用EF查询.换句话说,IQueryable没有完成任何工作,而且很懒.当foreach实际上需要该信息时,IQueryable会去获取它,届时上下文已经被处置.

Your first issue about the context being disposed is because the EF query is invoked only when you enumerate the actual IQueryable, in this case, at the foreach. In other words, the IQueryable has done no work and is lazy. When the foreach actually NEEDS the information the IQueryable goes to fetch it, by which time the context has already been disposed.

第二,由于您使用的是其他环境,因此您无法在刚刚获得的姿势上进行操作. EF会抱怨post对象仍然附加在旧的上下文中.本期将突出显示一个更一般的模式.您应该将上下文保留的时间与您的工作单元"一样长.一般来说,您在调用DbContext.SaveChanges()之后进行处置.

Secondly you can't do work on the pose you just got, because you are using another context. EF will complain that the post object is still attached to the old context. This issue will highlight a more general pattern. You should hold your context for as long as your "unit of work". Generally speaking you dispose after you call DbContext.SaveChanges().

这使我想到了您的第三个错误.您没有调用DbContext.SaveChanges().此代码将不会发生任何事情.您将不会写数据库,也不会运行EF验证,除了将要超出范围的内存以外,什么都不会发生.

This leads me to your third bug. You didn't call DbContext.SaveChanges(). Nothing is going to happen with this code. You are not going to write to the database, EF validation isn't going to run, nothing will happen except in memory, which is about to go out of scope.

最后,您的测试方法会产生副作用(假设它将成功保存).这将导致痛点进一步恶化.解决此问题的一种方法是在测试之前开始事务,然后在测试之后回滚.

Finally your test method is producing side effects (assuming it will successfully save). This will lead to pain points further down the line. A way to get around this is to begin a transaction before the test, and rollback after the test.

我了解,如果您想走这条路,MbUnit将为您执行事务逻辑.

I understand that MbUnit will do the transaction logic for you if you wish to go down that road.

总而言之,这就是我要做的...假设我了解您要实现的目标-

So to sum up, this is what I WOULD do...assuming I understand what you are trying to achieve-

从风格上讲,我讨厌CRUD方法.当您拥有Linq时,可以使用诸如GetPostByName之类的方法.我遇到的问题包括,还有更多代码需要维护(如果切换到nHibernate,则需要重新实现GetPostByName).其次,接下来您将发现需要GetPostByDescript,GetPostById,GetPostByDescriptionOrName ... etc等...

From a stylistic point I hate CRUD methods. Methods like GetPostByName, when you have Linq for that. The problems I have with it include, more code to maintain (if you change over to nHibernate, you need to reimplement GetPostByName). Secondly you will then next find you need a GetPostByDescript, then a GetPostById then a GetPostByDescriptionOrName...etc etc...

PS.我以ThePost之类的名字假设您是在单个实例之后....

PS. With a name like ThePost I assume you are after a single instance....

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

这篇关于为什么dbcontext被放置在foreach循环之前的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆