2

現在、カートに商品を追加するとき、私の追加アクションは(注文明細オブジェクト)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してカートをアタッチしようとします。CartRepsitoryAttachCart

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

1 に答える 1

1

カートをセッションに入れるとき、そのコンテキストからオブジェクトを切り離していますか? エンティティ オブジェクトはコンテキストを保持するため、追加する前に明示的にデタッチする必要があります。

于 2012-08-24T22:09:26.207 に答える