Wenn ich derzeit ein Produkt in meinen Warenkorb lege, wird die Aktion "Hinzufügen" meines CartController
wird aufgerufen mit der orderEntryDisplayViewModel
(das Objekt der Auftragszeile).
[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") });
}
Bevor sie erreicht wird, muss die CartModelBinder
erstellt oder holt den Einkaufswagen aus der Sitzung.
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;
}
}
Wenn in der Sitzung noch kein Einkaufswagen existiert, wird ein neuer mit dem Befehl CartRepository
CreateCart
Methode, die dann den neu erstellten Einkaufswagen zum Kontext hinzufügt.
public Cart CreateCart(bool saveCart = false)
{
Cart cart = new Cart();
context.Carts.Add(cart);
if (saveCart)
{ context.SaveChanges(); }
return cart;
}
Bevor ich das Cart-Objekt der Sitzung hinzufüge, löse ich es aus dem Kontext mit CartRepository
DetachCart
, fügen Sie sie der Sitzung hinzu und fügen Sie sie dann wieder dem Kontext hinzu.
public void DetachCart(Cart cart)
{
((IObjectContextAdapter)context).ObjectContext.Detach(cart);
}
En CartRepository
erhält den Kontext von 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"];
}
}
Si CartModelBinder
einen Wagen in der Sitzung findet, versucht er, den Wagen über die CartRepsitory
Methode AttachCart
.
public void AttachCart(Cart cart)
{
context.Carts.Attach(cart);
}
Am Ende der Aktion Hinzufügen in der Datei CartController
Ich leite zur Index-Aktion um, um die Warenkorbansicht anzuzeigen. Die Index-Aktion erfordert auch das Cart-Objekt, also CartModelBinder
wird ein zweites Mal aufgerufen und ruft dieses Mal die CartRepository
AttachCart
Methode. Mein Fehler tritt bei der AttachCart
Methode
"Ein Entitätsobjekt kann nicht von mehreren Instanzen von IEntityChangeTracker referenziert werden."
Ich habe dieses Problem eine gute Menge recherchiert und es scheint nicht, dass ich eine Situation haben, wo ich das Warenkorb-Objekt zu zwei Instanzen des Kontextes hinzufügen, wie scheint oft der Grund für den Fehler sein. Es scheint fast so, als ob das in der Sitzung gespeicherte Cart-Objekt mit Tracking-Informationen geändert wird, so dass EF beim Versuch, es in der nächsten HTTP-Anfrage anzuhängen, denkt, dass es an einen aktiven Kontext angehängt ist, aber in Wirklichkeit ist es der Kontext aus der vorherigen Anfrage. Ich habe ein Forum gefunden, in dem vorgeschlagen wurde, das Entity-Objekt zu lösen, bevor es der Sitzung hinzugefügt wird, aber ich habe das getan und habe immer noch das gleiche Problem.
Ich hoffe, ich habe bei dieser Erklärung nichts übersehen.
ANTWORT Dank an 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);
}