2

目前,当将产品添加到我的购物车时,我的 Add 操作CartController是使用orderEntryDisplayViewModel(订单行对象)调用的。

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

在到达之前,CartModelBinder要么从会话中创建或获取购物车。

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

如果会话中当前不存在购物车CartRepository CreateCart,则通过将新创建的购物车添加到上下文的方法创建一个新的购物车。

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

在将购物车对象添加到会话之前,我使用 将其从上下文中分离出来CartRepository DetachCart,将其添加到会话中,然后再次将其附加到上下文中。

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

从以下CartRepository位置获取上下文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"];
        }
    }

如果CartModelBinder在会话中找到购物车,则它会尝试通过CartRepsitory方法附加购物车AttachCart

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

在添加操作结束时,CartController我重定向到索引操作以显示购物车视图。index 操作也需要 Cart 对象,因此CartModelBinder第二次调用该对象,这次调用该CartRepository AttachCart方法。我的错误发生在AttachCart方法上

“一个实体对象不能被多个 IEntityChangeTracker 实例引用。”

我已经对此问题进行了大量研究,但似乎我没有将购物车对象添加到上下文的两个实例中的情况,这似乎通常是错误的原因。似乎存储在会话中的购物车对象正在使用跟踪信息进行修改,因此当我尝试在下一个 HTTP 请求中附加它时,EF 认为它已附加到活动上下文,但实际上它是上一个请求的上下文。我发现一个论坛建议我需要在将实体对象添加到会话之前将其分离,但我已经这样做了,但仍然遇到同样的问题。

希望我在这个解释中没有遗漏任何内容。

答案感谢 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);
    }
4

1 回答 1

1

当您将购物车放入会话时,您是否将对象从该上下文中分离出来?实体对象将携带上下文,因此您需要在添加之前显式分离它。

于 2012-08-24T22:09:26.207 回答