Save Header Detail EntityFramework

0

I am developing an application where I need to keep an invoice, where the client and the detail of said invoice, here the code:

using(Context context = new Context())
{
    Cliente cliente;
    if (clienteActual != consumidorFinal)
    {
        cliente = new Cliente()
        {
            Nombre = txtClienteNombre.Text.Trim(),
            Cedula = txtClienteCedula.Text.Trim(),
            Status = Status.Activo
        };
        context.Cliente.Add(cliente);
    }
    else
    {
        cliente = ClienteActual;
    }

    context.Cliente.Attach(cliente);
    cliente.CabeceraFactura = new List<CabeceraFactura>();
    CabeceraFactura cabeceraFactura = new CabeceraFactura()
    {
        Fecha = DateTime.Today,
        Status = Status.Activo,
        Cliente = cliente
    };

    cabeceraFactura.DetalleFactura = new List<DetalleFactura>();
    decimal total = 0;

    foreach (DetalleFactura entry in detalleFacturaBindingSource)
    {
        total += (entry.PrecioUnitario * entry.Cantidad);
        cabeceraFactura.DetalleFactura.Add(entry);
    }

    cabeceraFactura.Total = total;
    cliente.CabeceraFactura.Add(cabeceraFactura);
    context.SaveChanges();
    return true;
}

The problem is that I jump

  

System.InvalidOperationException :
  An entity object can not be referenced by multiple instances of IEntityChangeTracker.

    
asked by Andy 05.01.2018 в 05:15
source

2 answers

0

You can not use .Add() and .Attach() on the same object since I would add it twice to ChangeTracker and therefore it fails (with the error you indicate). Therefore:

if (clienteActual != consumidorFinal)
{
    cliente = new Cliente()
    {
        Nombre = txtClienteNombre.Text.Trim(),
        Cedula = txtClienteCedula.Text.Trim(),
        Status = Status.Activo
    };
    context.Cliente.Add(cliente);
}
else
{
    cliente = ClienteActual;
    context.Cliente.Attach(cliente);
}

In this way you make sure you do not call both methods.

On the other hand, if you add an item to a collection that belongs to a foreign key, it is not necessary to load the item in the other part of the relationship:

CabeceraFactura cabeceraFactura = new CabeceraFactura()
{
    Cliente = cliente // esta forma
};
cliente.CabeceraFactura.Add(cabeceraFactura); // o esta forma

The 2 provoke the same, but only one is necessary. EF will load the other part automatically.

As a last comment, since you use EF6, you should see using await context.SaveChangesAsync() and asynchronous programming.

    
answered by 05.01.2018 в 10:55
0

The problem is that you can not add an entity to a context when it belongs to another context, here the corrected code:

using(Context context = new Context())
        {
            Cliente cliente;
            if (clienteActual != consumidorFinal)
            {
                if (checkBoxNuevo.Checked)
                {
                    cliente = new Cliente()
                    {
                        Nombre = txtClienteNombre.Text.Trim(),
                        Cedula = txtClienteCedula.Text.Trim(),
                        Status = Status.Activo
                    };
                    context.Cliente.Add(cliente);
                }
                else
                {
                    cliente = context.Cliente.Where(c => c.Id == ClienteActual.Id).FirstOrDefault();
                }
            }
            else
            {
                cliente = context.Cliente.Where(c => c.Id == 1).FirstOrDefault();
            }
            CabeceraFactura cabeceraFactura = new CabeceraFactura()
            {
                Fecha = DateTime.Today,
                Status = Status.Activo,
                Cliente = cliente
            };
            decimal total = 0;
            foreach (DetalleFactura entry in detalleFacturaBindingSource)
            {
                total += (entry.PrecioUnitario * entry.Cantidad);
                cabeceraFactura.DetalleFactura.Add(new DetalleFactura() {
                    IdProducto = entry.IdProducto,
                    Cantidad = entry.Cantidad,
                    PrecioUnitario = entry.PrecioUnitario,
                    Subtotal = entry.Subtotal,
                    Status = Status.Activo
                });
            }
            cabeceraFactura.Total = total;
            cabeceraFactura.IdCliente = cliente.Id;
            context.CabeceraFactura.Add(cabeceraFactura);
            context.SaveChanges();
            return true;
        }
    
answered by 05.01.2018 в 16:05