Introducción

Hemos llegado al final de nuestra serie de artículos acerca de como dar nuestros primeros pasos con ef core 2. En este ultimo articulo vamos a ver como actualizar y eliminar objetos relaciones en ef core 2.

Como venimos haciendo, veremos ambos casos tanto en un contexto conectado como también desconectado.

Actualizar un objeto relacionado

Supongamos que tenemos que actualizar el ultimo estacionamiento de nuestro primer vehículo cargado en el sistema. La consulta en LINQ quedaría de la siguiente forma

private static void UpdateCheckoutParking()
{
    var firstVehicle = _context.Vehicles
                                .Include(p => p.Parkings)
                                .FirstOrDefault();

    var lastParking = firstVehicle.Parkings.LastOrDefault();
    lastParking.CheckOut = DateTime.Now;

    _context.SaveChanges();
}

Obtenemos el primer vehículo y todos los estacionamientos asociados al mismo a través del método Include(). Obtenemos el ultimo estacionamiento del vehículo a través de la clausula LastOrDefault() y actualizamos el campo CheckOut a la fecha actual.

Los comandos SQL que ejecuta ef core 2 son los siguientes

update-related-efCore2
update-related-efCore2

La primera y la segunda consulta es donde se obtiene el primer vehículo y la lista de estacionamientos asociados usando el id del vehículo que recupero en la consulta anterior. Por ultimo, ejecuta la actualización aplicando el cambio únicamente en el campo que se modifico.

Actualizar un objeto relacionado en un contexto desconectado

Ejecutemos el mismo procedimiento, pero esta vez, para un contexto desconectado. Utilizaremos una nueva instancia de nuestro contexto para simular este escenario.

private static void UpdateCheckoutParkingAnotherInstance()
{
    var firstVehicle = _context.Vehicles
                                .Include(p => p.Parkings)
                                .FirstOrDefault();

    var lastParking = firstVehicle.Parkings.LastOrDefault();
    lastParking.CheckOut = DateTime.Now;

    using (var newContext = new ParkingContext())
    {
        newContext.Parkings.Update(lastParking);
        newContext.SaveChanges();
    }
}

Observemos el comportamiento de este codigo. Los comandos SQL que ejecuta ef core 2 son los siguientes

update-related-disc-wrong-efCore2
update-related-disc-wrong-efCore2

Las dos primeras consultas son iguales al procedimiento anterior pero en este caso esta ocurriendo un comportamiento extraño. Ef core 2 esta actualizando el vehículo y los dos estacionamientos que se obtuvieron en las consultas anteriores. Son dos estacionamientos porque localmente tengo almacenado dos estacionamientos.

¿Qué esta ocurriendo?

update-related-err1
update-related-err1

Como verán, el objeto estacionamiento (parking) sigue trackeado al vehículo que a su vez esta asociada con los dos estacionamientos y ef core 2 trackea a cada uno de ellos. Es por eso que aplica la actualización para los tres objetos.

¿Cual es la solución?

Debemos usar el método Entry, lo cual el contexto se enfocará únicamente en la entrada que le pasemos. En nuestro caso, será nuestro objeto modificado parking

private static void UpdateCheckoutParkingAnotherInstance()
{
    var firstVehicle = _context.Vehicles
                                .Include(p => p.Parkings)
                                .FirstOrDefault();

    var lastParking = firstVehicle.Parkings.LastOrDefault();
    lastParking.CheckOut = DateTime.Now;

    using (var newContext = new ParkingContext())
    {
        newContext.Entry(lastParking).State = EntityState.Modified;
        newContext.SaveChanges();
    }
}

Los comandos SQL que ejecuta ef core 2 son los siguientes

update-related-disc-efCore2
update-related-disc-efCore2

Solo actualizo únicamente nuestro objeto lastParking.

Eliminar un objeto relacionado

Eliminemos el objeto que hemos actualizado anteriormente. Recordemos que para eliminar objetos usábamos el método Remove de DbSet.

private static void DeleteRelatedParking()
{
    var firstVehicle = _context.Vehicles
                                .Include(p => p.Parkings)
                                .FirstOrDefault();

    var lastParking = firstVehicle.Parkings.LastOrDefault();

    _context.Parkings.Remove(lastParking);
    _context.SaveChanges();
}

Los comandos SQL que ejecuta ef core 2 son los siguientes

delete-related-efCore22
delete-related-efCore2

Se vuelven aplicar las dos consultas para obtener el ultimo estacionamiento del primer vehículo y procedemos a eliminar el objeto de nuestra base de datos.

Eliminar un objeto relacionado en un contexto desconectado

El comportamiento extraño que ocurría en la actualización, también ocurre cuando queremos eliminar objetos en un contexto desconecto de ef core 2. En este caso, debemos cambiar el estado de la entrada a EntityState.Deleted para que ef core 2 ejecute el comando delete para el objeto en cuestión.

private static void DeleteRelatedParkingAnotherInstance()
{
    var firstVehicle = _context.Vehicles
                                .Include(p => p.Parkings)
                                .FirstOrDefault();

    var lastParking = firstVehicle.Parkings.LastOrDefault();

    using (var newContext = new ParkingContext())
    {
        newContext.Entry(lastParking).State = EntityState.Deleted;
        newContext.SaveChanges();
    }
}

Los comando SQL que ejecuta ef core 2 son los siguientes

delete-related-disc-efCore2
delete-related-disc-efCore2

Como verán, ejecuta el comando delete únicamente para nuestro objeto parking.

GITHUB /mpetrinidev

/blog-parking-ef-core-2

Branch [upd-del-related-objects]

¡Si te gusto el articulo, compártelo con tus contactos en las redes sociales!

Escribe una respuesta a este comentario

avatar
500
  Subscribe  
Notificar de