Error saving data from a session in the database

Asked

Viewed 402 times

0

I am developing a sales system. Follow the link: Save Request - ASP.NET MVC

However when finalizing the purchase and saving the data in the bank, I get the following error:

"An Entity Object cannot be referenced by Multiple instances of Ientitychangetracker"

How can I fix this?

public ActionResult SalvarCarrinho() 
{
    var carrinho = Session["Carrinho"] != null ? (Pedido)Session["Carrinho"] : new Pedido();

    contexto.Pedidos.Add(carrinho);
    contexto.SaveChanges();

    return RedirectToAction("Carrinho");
}

Gives error in this line:

 contexto.Pedidos.Add(carrinho);

Complete code of Controller:

public ActionResult AdicionarCarrinho(int id)
{
    Pedido carrinho = Session["Carrinho"] != null ? (Pedido)Session["Carrinho"] : new Pedido();

    var produto= db.Produto.Find(id);

    if (produto != null)
    {
        var itemPedido = new ItemPedido();
        itemPedido.Produto = produto;
        itemPedido.Qtd = 1;


        if (carrinho.ItemPedido.FirstOrDefault(x => x.IdProduto == produto.IdProduto) != null)
        {
            carrinho.ItemPedido.FirstOrDefault(x => x.IdProduto == produto.IdProduto).Qtd += 1;
        }
        else
        {
            carrinho.ItemPedido.Add(itemPedido);
        }



        carrinho.ValorTotal = carrinho.ItemPedido.Select(i => i.Pedido).Sum(d => d.Preco);

        Session["Carrinho"] = carrinho;
    }

    return RedirectToAction("Carrinho");
}

public ActionResult Carrinho()
{
    Pedido carrinho = Session["Carrinho"] != null ? (Pedido)Session["Carrinho"] : new Pedido();

    return View(carrinho);
}


public ActionResult Remover(int id)
{
    var carrinho = Session["Carrinho"] != null ? (Pedido)Session["Carrinho"] : new Pedido();
    var itemExclusao = carrinho.ItemPedido.FirstOrDefault(i => i.IdItemPedido == id);
    carrinho.ItemPedido.Remove(itemExclusao);

    Session["Carrinho"] = carrinho;
    return RedirectToAction("Carrinho");
}

public ActionResult FinalizarCarrinho()
{
    var carrinho = Session["Carrinho"] != null ? (Pedido)Session["Carrinho"] : new Pedido();

    var id = Convert.ToInt32(Session["IdUsuario"]);
    var usuario = db.Usuario.FirstOrDefault(u => u.IdUsuario == id);
    carrinho.DtPedido = DateTime.Now;
    carrinho.Usuario = usuario;
    carrinho.StatusPedido = "esperando pagamento";
    carrinho.TipoPag = "boleto";
    db.Pedido.Add(carrinho);
    db.SaveChanges();

    return RedirectToAction("Carrinho");
}
  • 2

    Now you put the code that is giving problem in the body of the question, please.

  • That’s the code right there.

  • 1

    I believe it is the fact that there is more than one context somewhere. The code is unclear on this. How is the statement of contexts?

  • you want to see the requested classes etc?

  • No, I want the code of Controller.

  • I did not use the guid because the Iditempedido is generated alone by the database.

  • I’ve already updated what you asked for.

Show 2 more comments

1 answer

1


I don’t remember saying that in another answer, but possibly the cause of the problem is this:

var itemPedido = new ItemPedido();
itemPedido.Produto = design; // Aqui você definiu um Produto (e de forma errada)
itemPedido.Qtd = 1;
itemPedido.IdProduto = produto.IdProduto; // Então aqui vai dar problema

Considering that you have made the decision to use Id as a sequential integer, the chance to confuse the Entity Framework is great. I explain:

When defining an id this way:

itemPedido.IdProduto = produto.IdProduto;

You’re forcing on an object uncharted in context an Id of an object mapped in context. And here:

itemPedido.Produto = design;

You’re putting another object (which I don’t know where it came from, because it’s possibly a collage of another answer I gave) that I don’t know if is mapped in context or not. By doing this, you’re basically creating a produto that does not exist (or at least the context understands so), because it is the Id of an object with the content of another object.

In this case, complete itemPedido.IdProduto is totally unnecessary, since you are already filling itemPedido.Produto. One should avoid filling in a foreign key id directly, as the Entity Framework may understand that it is a new object (very likely to be your problem) and insert something into the database that should not.

Same thing for this code:

carrinho.IdUsuario = Convert.ToInt32(Session["IdUsuario"]);

The correct is for you to select the user and assign the object to Usuario to the cart, so that the Entity Framework understands where this user came from:

var usuarioId = Convert.ToInt32(Session["IdUsuario"]);
var usuario = db.Usuarios.FirstOrDefault(u => u.IdUsuario == usuarioId);
carrinho.Usuario = usuario;

EDIT

Based on the comments, it seems that the objects that go to the session are guarding the reference of a context that no longer exists, so before inserting products in the order, do the following:

var produto = db.Produto.Find(id);
db.Entry(produto).State = EntityState.Detached;

if (produto != null)
{
    var itemPedido = new ItemPedido();
    itemPedido.Produto = produto;
    itemPedido.Qtd = 1;

    ...

This ensures that you will be working with contextual highlighted objects.

To save, you need to put the objects in context:

public ActionResult FinalizarCarrinho()
{
    var carrinho = Session["Carrinho"] != null ? (Pedido)Session["Carrinho"] : new Pedido();

    var id = Convert.ToInt32(Session["IdUsuario"]);
    var usuario = db.Usuario.FirstOrDefault(u => u.IdUsuario == id);

    foreach (var itemPedido in carrinho.ItemPedido) {
        db.Produtos.Attach(itemPedido.Produto);
    }

    carrinho.DtPedido = DateTime.Now;
    carrinho.Usuario = usuario;
    carrinho.StatusPedido = "esperando pagamento";
    carrinho.TipoPag = "boleto";
    db.Pedido.Add(carrinho);
    db.SaveChanges();

    return RedirectToAction("Carrinho");
}

I have not tested this solution, but I believe it should work.

  • I removed the other lines, and left only this: itemPedido.Product = product but still giving the same error. I’ll post how the code is currently.

  • I updated the way you indicated, but the error continues.

  • I still have one question: where is this context and how do you initiate it? The impression it gives is that it is being initialized N times, which is what the error says.

  • I’m not sure I understand. But I call the database classes through this line that I set at the beginning of the controller: private Entities db = new Entities();

  • I think I know what it is. I’ll edit the answer.

  • @Guilhermevinicius Look now.

  • These "methods" attach and dettach have to make changes in the classes, because he is not recognizing and the error in this line?

  • True. Look now.

  • Guy the attach he found but the dettach did not.

  • @Guilhermevinicius Changed the syntax. Use db.Entry(produto).State = EntityState.Detached;.

  • 1

    Now it worked. Thank you very much, you saved my ass here.

Show 6 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.