現在、カートに商品を追加するとき、私の追加アクションは(注文明細オブジェクト)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
[インデックス]アクションにリダイレクトして、カートビューを表示します。インデックスアクションにはCartオブジェクトも必要なのでCartModelBinder
、2回目に呼び出され、今回はCartRepository
AttachCart
メソッドを呼び出します。AttachCart
メソッドでエラーが発生します
「エンティティオブジェクトは、IEntityChangeTrackerの複数のインスタンスから参照できません。」
私はこの問題をかなり調査しましたが、カートオブジェクトをコンテキストの2つのインスタンスに追加しているという状況はないようです。これは、エラーの原因であることが多いようです。セッションに保存されているカートオブジェクトが追跡情報で変更されているように見えるため、次のHTTPリクエストでアタッチしようとすると、EFはアクティブなコンテキストにアタッチされていると見なしますが、実際には前のリクエストのコンテキストです。セッションに追加する前にエンティティオブジェクトをデタッチする必要があることを示唆するフォーラムを見つけましたが、それを実行しても同じ問題が発生します。
うまくいけば、私はこの説明で何も見逃していません。
答えMarkOretaに感謝します
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);
}