ASP.NET MVC3和实体与错误框架v4.1中的实体对象不能由IEntityChangeTracker的多个实例被引用 [英] ASP.NET MVC3 and Entity Framework v4.1 with error An entity object cannot be referenced by multiple instances of IEntityChangeTracker

查看:108
本文介绍了ASP.NET MVC3和实体与错误框架v4.1中的实体对象不能由IEntityChangeTracker的多个实例被引用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目前,当用户将产品添加到我的购物车的添加操作我的 CartController 被称为与 orderEntryDisplayViewModel (中订单行对象)。

  [HttpPost]
    公共RedirectToRouteResult添加(车车,OrderEntryDisplayViewModel订单行)
    {
        如果(!ModelState.IsValid)
        {返回RedirectToAction(显示,订单条目,新产品{= orderLine.Line.PartNum}); }
        CompleteProduct产品= NULL;
        orderLine.Line.RequestedShipDate = orderLine.RequestedShipDate;
        如果(orderLine.Line.NewMyPartNum!= NULL)
        {orderLine.Line.MyPartNum = orderLine.Line.NewMyPartNum; }
        尝试
        {
            产品= _inventoryRepo.FetchByPartNum(orderLine.Line.PartNum,User.Identity.Name);
            orderLine.Line.Product =产品;
            cart.AddItem(orderLine.Line);
            // _ cartRepo.Save();
        }
        赶上(DbUpdateException E)
        {抛出; }
        抓住
        {
            ModelState.AddModelError(,问题的一部分添加到购物车);
            返回RedirectToAction(指数,新的{RETURNURL = Url.Action(指数,订单条目)});
        }
        返回RedirectToAction(指数,新的{RETURNURL = Url.Action(指数,订单条目)});
    }

达到

在它的 CartModelBinder 创建或者从会话获取购物车。

 公共类CartModelBinder:IModelBinder
{
    私人常量字符串sessionKey =购物车;    公共对象BindModel(ControllerContext controllerContext,ModelBindingContext的BindingContext)
    {
        CartRepository cartRepo =新CartRepository();
        车车=(车)controllerContext.HttpContext.Session [sessionKey]
        如果(车== NULL)
        {
            购物车= cartRepo.CreateCart(真);
            cartRepo.DetachCart(车);
            controllerContext.HttpContext.Session [sessionKey] =车;
            cartRepo.AttachCart(车);
        }
        其他
        {cartRepo.AttachCart(车); }
        返回购物车;
    }
}

如果没有车目前存在会话创建一个新的虽然 CartRepository CreateCart 方法,然后添加新创建的车到上下文。

 大众车CreateCart(布尔saveCart = FALSE)
    {
        车车=新的购物车();
        context.Carts.Add(车);
        如果(saveCart)
        {context.SaveChanges(); }
        返回购物车;
    }

在我的车对象添加到会话我使用分离它从上下文 CartRepository DetachCart ,添加到会话,然后重新连接上下文。

 公共无效DetachCart(车车)
{
    ((IObjectContextAdapter)上下文).ObjectContext.Detach(车);
}

CartRepository 获取从上下文 ContextHelper

 公共静态类ContextHelper
{
    公共静态InsideIIMAKContext InsideIIMAK
    {
        得到
        {
            如果(HttpContext.Current.Items [InsideIIMAKContext] == NULL)
            {HttpContext.Current.Items.Add(InsideIIMAKContext,新InsideIIMAKContext()); }
            返回(InsideIIMAKContext)HttpContext.Current.Items [InsideIIMAKContext];
        }
    }

如果 CartModelBinder 中发现的会议上车,然后它试图通过 CartRepsitory 方法<$附上车C $ C> AttachCart 。

 公共无效AttachCart(车车)
    {
        context.Carts.Attach(车);
    }

在添加操作的结束 CartController 我重定向到Index操作来显示车查看。该指数操作需要车对象太让 CartModelBinder 被称为第二次,这一次调用 CartRepository AttachCart 方法。在我出现错误 AttachCart


  

的实体对象不能由多个实例引用
  IEntityChangeTracker。


我已经研究了这个问题一个良好的金额,它似乎并不认为我有哪里我加入购物车对象上下文的两个实例一样,似乎往往是错误原因的情况。它几乎好像存储在会话车对象被与跟踪信息,所以当我尝试将它附着在接下来的HTTP请求EF认为它是连接到一个活跃的背景下修改的,但实际上它是一个从$ P $上下文pvious请求。我发现了一个论坛,建议我需要将它添加到会议之前分离的实体对象,但我做到了这一点,仍然有同样的问题。

希望我没有错过这个解释什么。

答案感谢马克Oreta

 公共无效DetachCart(车车)
    {
        变种的ObjectContext =((IObjectContextAdapter)上下文).ObjectContext;
        objectContext.Detach(cart.Customer);
        的foreach(在cart.Lines VAR项)
        {objectContext.Detach(项目); }
        objectContext.Detach(车);
    }


解决方案

当你把车到会话,你从分离这方面的目标?实体对象将随身携带的背景下,所以你需要明确之前,将其卸下。

Currently when adding a product to my cart the Add action of my CartController is called with the orderEntryDisplayViewModel (the order line object).

    [HttpPost]
    public RedirectToRouteResult Add(Cart cart, OrderEntryDisplayViewModel orderLine)
    {
        if (!ModelState.IsValid)
        { return RedirectToAction("Display", "OrderEntry", new { Product = orderLine.Line.PartNum }); }
        CompleteProduct product = null;
        orderLine.Line.RequestedShipDate = orderLine.RequestedShipDate;
        if (orderLine.Line.NewMyPartNum != null)
        { orderLine.Line.MyPartNum = orderLine.Line.NewMyPartNum; }
        try
        {
            product = _inventoryRepo.FetchByPartNum(orderLine.Line.PartNum, User.Identity.Name);
            orderLine.Line.Product = product;
            cart.AddItem(orderLine.Line);
            //_cartRepo.Save();
        }
        catch (DbUpdateException e)
        { throw; }
        catch
        {
            ModelState.AddModelError("", "Problem adding part to cart");
            return RedirectToAction("Index", new { returnUrl = Url.Action("Index", "OrderEntry") });
        }
        return RedirectToAction("Index", new { returnUrl = Url.Action("Index", "OrderEntry") });
    }

Before it is reached the CartModelBinder either creates or gets the shopping cart from the session.

public class CartModelBinder : IModelBinder
{
    private const string sessionKey = "Cart";

    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        CartRepository cartRepo = new CartRepository();
        Cart cart = (Cart)controllerContext.HttpContext.Session[sessionKey];
        if (cart == null)
        {
            cart = cartRepo.CreateCart(true);
            cartRepo.DetachCart(cart);
            controllerContext.HttpContext.Session[sessionKey] = cart;
            cartRepo.AttachCart(cart);
        }
        else
        { cartRepo.AttachCart(cart); }
        return cart;
    }
}

If no cart currently exists in the session a new one is created though the CartRepository CreateCart method which then adds the newly created cart to the context.

    public Cart CreateCart(bool saveCart = false)
    {
        Cart cart = new Cart();
        context.Carts.Add(cart);
        if (saveCart)
        { context.SaveChanges(); }
        return cart;
    }

Before I add the cart object to the session I detach it from the context using CartRepository DetachCart, add it to the session, then attach it to the context again.

public void DetachCart(Cart cart)
{
    ((IObjectContextAdapter)context).ObjectContext.Detach(cart);
}

The CartRepository gets the context from ContextHelper:

public static class ContextHelper
{
    public static InsideIIMAKContext InsideIIMAK
    {
        get
        {
            if (HttpContext.Current.Items["InsideIIMAKContext"] == null)
            { HttpContext.Current.Items.Add("InsideIIMAKContext", new InsideIIMAKContext()); }
            return (InsideIIMAKContext)HttpContext.Current.Items["InsideIIMAKContext"];
        }
    }

If CartModelBinder finds a cart in the session then it attempts to attach the cart through the CartRepsitory method AttachCart.

    public void AttachCart(Cart cart)
    {
        context.Carts.Attach(cart);
    }

At the end of the Add action in the CartController I redirect to the Index action to display the cart view. The index action requires the Cart object too so CartModelBinder is called a second time and this time calls the CartRepository AttachCart method. My error occurs at the AttachCart method

"An entity object cannot be referenced by multiple instances of IEntityChangeTracker."

I've researched this issue a good amount and it doesn't seem that I have a situation where I am adding the cart object to two instances of the context like seems to often be the reason for the error. It almost seems as if the cart object stored in the session is being modified with tracking information so when I try to attach it in the next HTTP request EF thinks it is attached to an active context, but really it's the context from the previous request. I found a forum which suggested I needed to detach the Entity Object before adding it to the session, but I've done that and still have the same issue.

Hopefully I haven't missed anything in this explanation.

ANSWER Thanks to Mark Oreta

    public void DetachCart(Cart cart)
    {
        var objectContext = ((IObjectContextAdapter)context).ObjectContext;
        objectContext.Detach(cart.Customer);
        foreach (var item in cart.Lines)
        { objectContext.Detach(item); }
        objectContext.Detach(cart);
    }

解决方案

When you're putting the cart into the session, are you detaching the object from that context? Entity Objects will carry the context with them, so you'll need to explicitly detach it prior to adding it.

这篇关于ASP.NET MVC3和实体与错误框架v4.1中的实体对象不能由IEntityChangeTracker的多个实例被引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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