web-dev-qa-db-ja.com

DbContextがMVC 4を使用して破棄されたため、操作を完了できません

この質問は何度も聞かれることを知っています。すべてのソリューションを読んで実装しましたが、成功しませんでした。 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; }
    }
}     

はい、このエンティティにはナビゲーションプロパティがありますが、そのエンティティデータは必要ないので、それを含めたくありません。

ありがとう

20

発生している問題は、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クエリはdeferredです。つまり、コントローラーで実行されるのではなく、おそらくコレクションをループするビューで実行されます(列挙を強制し、LINQを実行します)。 usingステートメントを使用してDBコンテキストを破棄しているので(もちろんこれは良い習慣です)、コンテキストはビューに到達する前に破棄され、ビューは破棄されたコンテキストに対してコードを実行します。 usingステートメント内で列挙を強制すると、後でコンテキストが破棄されるときではなく、その時点でコードが実行され、この問題が防止されます。

60
Haney