目前,当将产品添加到我的购物车时,我的 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);
}