操作无法完成,因为 DbContext 已使用 MVC 4 处置

Posted

技术标签:

【中文标题】操作无法完成,因为 DbContext 已使用 MVC 4 处置【英文标题】:The operation cannot be completed because the DbContext has been disposed using MVC 4 【发布时间】:2014-02-08 08:56:40 【问题描述】:

我知道这个问题被问了很多次。我已阅读并实施了所有解决方案,但没有成功。当我使用 EF 从数据库中检索数据并在 View 上使用此模型后与模型绑定时,出现此错误。

我的控制器代码是

using System.Linq;
using System.Web.Mvc;
using JsonRenderingMvcApplication.Models;

namespace JsonRenderingMvcApplication.Controllers

    public class PublisherController : Controller
    
        public ActionResult Index()
        
            PublisherModel model = new PublisherModel();
            using (DAL.DevelopmentEntities context = new DAL.DevelopmentEntities())
                           
                model.PublisherList = context.Publishers.Select(x =>
                                        new SelectListItem()
                                        
                                            Text = x.Name,
                                            Value = x.Id.ToString()
                                        ); ;
                           
            return View(model);
        

    

我的查看代码是

@model JsonRenderingMvcApplication.Models.PublisherModel

@
    ViewBag.Title = "Index";

<div>
    @html.DisplayFor(model=>model.Id)
    @Html.DropDownListFor(model => model.Id, Model.PublisherList);
</div>
<div id="booksDiv">

</div>

我的型号代码是

using System.Collections.Generic;
using System.Web.Mvc;
using System.ComponentModel.DataAnnotations;

namespace JsonRenderingMvcApplication.Models

    public class PublisherModel
    
        public PublisherModel()
        
            PublisherList = new List<SelectListItem>();
        

        [Display(Name="Publisher")]
        public int Id  get; set; 
        public IEnumerable<SelectListItem> PublisherList  get; set; 
    

我的实体代码是

namespace JsonRenderingMvcApplication.DAL

    using System;
    using System.Collections.Generic;

    public partial class Publisher
    
        public Publisher()
        
            this.BOOKs = new HashSet<BOOK>();
        

        public int Id  get; set; 
        public string Name  get; set; 
        public string Year  get; set; 

        public virtual ICollection<BOOK> BOOKs  get; set; 
    
     

是的,这个实体有一个导航属性,但我不想要那个实体数据,所以我不想包含它。

谢谢

【问题讨论】:

哪一行抛出异常? @wdosanjos 这一行“@Html.DropDownListFor(model => model.Id, Model.PublisherList);”作为帖子标题引发异常 虽然与这个问题没有直接联系,但我发现同样的错误很有趣。我有这个 unitOfWork 类(具有 dbcontext 对象)和 ABC 类。 ABC 类通过 unitOfWork 类使用 dbContext 对象。 ABC 类和 unitOfWork 都通过温莎城堡 DI 容器实例化。我遇到了同样的错误,问题在于我在 DI 容器的初始化中注册类 ABC 的方式。我编写了类似 Register(Component.For().ImplementedBy() .LifeStyle.Transient ) 的代码,但我错过了粗体代码,最终导致了这个问题。跨度> 【参考方案1】:

您遇到的问题是由于 LINQ 的延迟执行造成的。对于尚未意识到 LINQ 如何在后台工作的开发人员来说,这无疑是一个难题。我有一篇很棒的博客文章,但核心概念是您必须对集合强制枚举以使 LINQ 代码立即运行而不是稍后运行。这意味着改变这一点:

model.PublisherList = context.Publishers.Select(x =>
    new SelectListItem()
    
        Text = x.Name,
        Value = x.Id.ToString()
    );

到这里:

model.PublisherList = context.Publishers.Select(x =>
    new SelectListItem()
    
        Text = x.Name,
        Value = x.Id.ToString()
    ).ToList();

注意那里的.ToList() 强制枚举。

您的 LINQ 查询是延迟,这意味着它不是在您的控制器上运行,而是在之后运行,可能在您循环遍历集合的视图中(这会强制枚举并因此运行 LINQ) .因为您使用using 语句来处理您的数据库上下文(这当然是一种很好的做法),所以在您到达视图之前就处理了上下文,该视图针对已处理的上下文执行代码。在using 语句中强制枚举将在那时运行代码,而不是在释放上下文时稍后运行,并防止此问题。

【讨论】:

优秀的答案。 @桑迪普。如果您对 .ToList() 的作用感到好奇,我强烈建议您阅读文档。 msdn.microsoft.com/en-us/library/bb342261%28v=vs.110%29.aspx @Sandeep 当然,请参阅 David 对 .ToList() 所做的事情的评论。它基本上会在您的可枚举中创建一个对象列表。 感谢@DavidL 分享此链接。如果我不正确,请纠正我。我知道“.ToList() 是 Enumerable 集合的扩展方法,并返回 IEnumerable 类型的列表。谢谢 @Sandeep 完全正确。但是List&lt;T&gt; 不支持延迟执行,因此代码会立即执行。 IEnumerable&lt;T&gt; 支持延迟执行,这对于跨多个投影/过滤器/查询的 LINQ 效率至关重要。这就是为什么 LINQ 几乎总是针对 IEnumerable&lt;T&gt;IQueryable&lt;T&gt; 接口工作的原因。 谢谢@DavidHaney。我得到了它。 +1

以上是关于操作无法完成,因为 DbContext 已使用 MVC 4 处置的主要内容,如果未能解决你的问题,请参考以下文章

使用 ObjectDataSource.Select() 方法最终会导致异常“操作无法完成,因为 DbContext 已被释放。”

C#:使用 IQueryable 注入 DbContext 时,无法访问 ASP.NET Core 中的已处置对象

通过 Azure 函数注入 DbContext 时无法访问已处置的对象

操作无法完成因为其中的文件夹或文件已在另一个程序中打开怎么解决

操作无法完成因为其中的文件夹或文件已在另一个程序中打开怎么解决

操作无法完成因为其中的文件夹或文件已在另一个程序中打开怎么解决