已经有一个必须先关闭的开放DataReader

Arm*_*ode 3 c# linq asp.net asp.net-mvc asp.net-mvc-4

在我的映射逻辑层(Model to ViewModel)中,我尝试SelectListItem在编辑视图中填充一个HTML.DropDownListFor帮助器.

我尝试使用以下代码示例中的查询来检索品牌名称列表以填充SelectListItem,但触发了以下异常:

已经有一个与此命令关联的打开DataReader,必须先关闭它.

制图

public class MedicalProductMapper
{
    private MvcMedicalStoreDb _db; // DataContext class

    public MedicalProductMapper(MvcMedicalStoreDb db)
    {
        _db = db;
    }    
    public MedicalProductViewModel GetMedicalProductViewModel(MedicalProduct source)
    {
        MedicalProductViewModel viewModel = new MedicalProductViewModel();

        viewModel.ID = source.ID; 
        viewModel.Name = source.Name;
        viewModel.Price = source.Price;
        viewModel.BrandID = source.BrandID;

        // This following line produces the exception
        viewModel.BrandName = _db.Brands.Single(b => b.ID == source.BrandID).Name;

        var queryBrands = from b in _db.Brands
                          select b;

        viewModel.BrandSelectListItem = queryBrands as IEnumerable<SelectListItem>;

        return viewModel;
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道通过在连接字符串中启用多个活动结果集(MARS)可以轻松解决问题,但我想知道是否有办法在不修改连接字符串的情况下执行我想要的操作.

这里有一些更多的类,以防它们有助于解决这个问题:

编辑视图

@model MvcMedicalStore.Models.MedicalProductViewModel

@{
    ViewBag.Title = "Edit";
}

<h2>Edit</h2>

@using (Html.BeginForm()) {
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>MedicalProduct</legend>

        @Html.HiddenFor(model => model.ID)

        <div class="editor-label">
            @Html.LabelFor(model => model.Name)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Name)
            @Html.ValidationMessageFor(model => model.Name)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Price)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Price)
            @Html.ValidationMessageFor(model => model.Price)
        </div>

        // BRAND NAME
        <div class="editor-label">
            @Html.LabelFor(model => model.BrandName)
        </div>
        <div class="editor-field">
            @Html.DropDownListFor(model => model.BrandName, Model.BrandSelectListItem)
            @Html.ValidationMessageFor(model => model.BrandName)
        </div>

        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}
Run Code Online (Sandbox Code Playgroud)

控制器:

public class MedicalProductController : Controller
{
    private MvcMedicalStoreDb _db = new MvcMedicalStoreDb();

    //
    // GET: /MedicalSupply/

    public ActionResult Index()
    {
        var viewModel = _db.Products.AsEnumerable()
            .Select(product => GetMedicalProductViewModel(product));
        return View(viewModel);
    }

    public MedicalProductViewModel GetMedicalProductViewModel(MedicalProduct product)
    {
        var mapper = new MedicalProductMapper(_db);

        return mapper.GetMedicalProductViewModel(product);            
    }
    public MedicalProduct GetMedicalProduct(MedicalProductViewModel viewModel)
    {
        var mapper = new MedicalProductMapper(_db);

        return mapper.GetMedicalProduct(viewModel);
    }

    //
    // GET: /MedicalSupply/Edit/5

    public ActionResult Edit(int id = 0)
    {
        MedicalProduct medicalProduct = _db.Products.Find(id);
        if (medicalProduct == null)
        {
            return HttpNotFound();
        }

        var viewModel = GetMedicalProductViewModel(medicalProduct);
        return View(viewModel);
    }

    //
    // POST: /MedicalSupply/Edit/5

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(MedicalProduct medicalProduct)
    {
        if (ModelState.IsValid)
        {
            _db.Entry(medicalProduct).State = EntityState.Modified;
            _db.SaveChanges();
            return RedirectToAction("Index");
        }

        var viewModel = GetMedicalProductViewModel(medicalProduct);
        return View(viewModel);
    }
}
Run Code Online (Sandbox Code Playgroud)

堆栈跟踪

[InvalidOperationException:已经有一个与此命令关联的打开DataReader,必须先关闭它.]
System.Data.SqlClient.SqlInternalConnectionTds.ValidateConnectionForExecute(SqlCommand command)+5287423
System.Data.SqlClient.SqlConnection.ValidateConnectionForExecute(String method,SqlCommand command )+20
System.Data.SqlClient.SqlCommand.ValidateCommand(String method,Boolean async)
+155 System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior,RunBehavior runBehavior,Boolean returnStream,String method,TaskCompletionSource`1 completion,Int32 timeout ,任务和任务,布尔asyncWrite)+82
System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior,RunBehavior runBehavior,Boolean returnStream,String method)+53
System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior,String method)+134
System.Data.SqlClient.SqlCommand. ExecuteDbDataReader(CommandBehavior behavior)+41
System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior)+10 System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand,CommandBehavior behavior)+437

[EntityCommandExecutionException:执行命令定义时发生错误.有关详细信息,请参阅内部异常.]
System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand,CommandBehavior behavior)+507
System.Data.Objects.Internal.ObjectQueryExecutionPlan.Execute(ObjectContext context,ObjectParameterCollection parameterValues)+730
System.Data. Objects.ObjectQuery 1.GetResults(Nullable1 forMergeOption)+131
System.Data.Objects.ObjectQuery 1.System.Collections.Generic.IEnumerable<T>.GetEnumerator() +36 System.Linq.Enumerable.Single(IEnumerable1 source)+179 System.Data.Objects.ELinq.ObjectQueryProvider.b_ 3(IEnumerable 1 query,Expression queryRoot)+59 System.Data.Objects.ELinq. ObjectQueryProvider.System.Linq.IQueryProvider.Execute(表达式表达式)+1331 sequence) +41
System.Data.Objects.ELinq.ObjectQueryProvider.ExecuteSingle(IEnumerable


System.Data.Entity.Internal.Linq.DbQueryProvider.Execute(表达式表达式)+123 System.Linq.Queryable.Single(IQueryable 1 source, Expression1谓词)+287
MvcMedicalStore.Mappers.MedicalProductMapper.GetMedicalProductViewModel(MedicalProduct source)in c:\ Users\Matt\Documents\Visual Studio 2012\Projects\MvcMedicalStore\MvcMedicalStore\Mappers\MedicalProductMapper.cs:28 MvcMedicalStore.Controllers.<> c
_DisplayClass1.b_ 0(MedicalProduct product)in c:\ Users\Matt\Documents\Visual Studio 2012\Projects\MvcMedicalStore\MvcMedicalStore\Controllers\HomeController.cs:28 System.Linq.WhereSelectEnumerableIterator 1 continuation)2.MoveNext() +145
ASP._Page_Views_Home_Index_cshtml.Execute() in c:\Users\Matt\Documents\Visual Studio 2012\Projects\MvcMedicalStore\MvcMedicalStore\Views\Home\Index.cshtml:25 System.Web.WebPages.WebPageBase.ExecutePageHierarchy() +197
System.Web.Mvc.WebViewPage.ExecutePageHierarchy() +119
System.Web.WebPages.StartPage.RunPage() +17
System.Web.WebPages.StartPage.ExecutePageHierarchy() +62
System.Web.WebPages.WebPageBase.ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage) +76
System.Web.Mvc.RazorView.RenderView(ViewContext viewContext, TextWriter writer, Object instance) +743
System.Web.Mvc.BuildManagerCompiledView.Render(ViewContext viewContext, TextWriter writer) +382
System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context) +431 System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult) +39
System.Web.Mvc.<>c__DisplayClass1a.<InvokeActionResultWithFilters>b__17() +74 System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func

+388 System.Web.Mvc.<> c _DisplayClass1c.b_19()+72 System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext,IList 1.End()+ 136 System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult,Object tag)+56 System.Web. Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult)+40 System.Web.Mvc.<> c1 filters, ActionResult actionResult) +303
System.Web.Mvc.Async.<>c__DisplayClass2a.<BeginInvokeAction>b__20() +155 System.Web.Mvc.Async.<>c__DisplayClass25.<BeginInvokeAction>b__22(IAsyncResult asyncResult) +184 System.Web.Mvc.Async.WrappedAsyncResult


_DisplayClass1d.b_ 18(IAsyncResult asyncResult)+40
System.Web.Mvc.Async.<> c
_DisplayClass4.b_ 3(IAsyncResult ar )+47 System.Web.Mvc.Async.WrappedAsyncResult 1.End()+ 151 System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult,Object tag)+591.End() +151
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +59
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +40
System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +44 System.Web.Mvc.Async.<>c__DisplayClass4.<MakeVoidDelegate>b__3(IAsyncResult ar) +47 System.Web.Mvc.Async.WrappedAsyncResult


System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult,Object tag)+40 System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult)+39
System.Web.Mvc.Controller.System.Web.Mvc.Async .IAsyncController.EndExecute(IAsyncResult asyncResult)+39
System.Web.Mvc.<> c
_DisplayClass8.b_ 3(IAsyncResult asyncResult)+45
System.Web.Mvc.Async.<> c
_DisplayClass4.b__3(IAsyncResult ar)+47 System .Web.Mvc.Async.WrappedAsyncResult`1.End()+ 151
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult,Object tag)+59
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult ,对象标签)+40
System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult)+40 System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result)+38
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.执行()+9628700 System.Web.HttpApplication.ExecuteStep(IExecutionStep step,Boolean&completedSynchronously)+155

Gre*_*ire 5

您在每个产品的选择中提出另一个请求.但是您的产品被枚举,因此第一个datareader没有关闭.这就是您打开多个数据加载器的原因.

public ActionResult Index()
{
    var products = _db.Products.ToArray() // force loading the results from database 
                                           // and close the datareader

    var viewModel = products.Select(product => GetMedicalProductViewModel(product));

    return View(viewModel);
}
Run Code Online (Sandbox Code Playgroud)

附加:我认为您应该优化您的模型创建:您为数据库中的每个产品提出相同的请求(选择品牌).

为避免不必要的多个数据库往返,您应该:

  1. 加载您的产品
  2. 加载你的品牌
  3. 使用一个产品和从步骤2中获取的品牌来构建模型