Compartir a través de


Guardar datos

Aunque la consulta permite leer datos de la base de datos, guardar datos significa agregar nuevas entidades a la base de datos, quitar entidades o modificar las propiedades de las entidades existentes de alguna manera. Entity Framework Core (EF Core) admite dos enfoques fundamentales para guardar datos en la base de datos.

Enfoque 1: seguimiento de cambios y guardar cambios

En muchos escenarios, el programa debe consultar algunos datos de la base de datos, realizar alguna modificación en ella y guardar esas modificaciones de nuevo; esto a veces se conoce como una "unidad de trabajo". Por ejemplo, supongamos que tiene una serie de blogs y quisiera modificar la propiedad Url de uno de ellos. En EF, esto suele hacerse de la siguiente manera:

using (var context = new BloggingContext())
{
    var blog = await context.Blogs.SingleAsync(b => b.Url == "http://example.com");
    blog.Url = "http://example.com/blog";
    await context.SaveChangesAsync();
}

El código anterior realiza los pasos siguientes:

  1. Usa una consulta LINQ normal para cargar una entidad desde la base de datos (consulte Datos de consulta). Las consultas de EF realizan seguimiento por defecto, lo que significa que EF sigue las entidades cargadas en su seguimiento de cambios interno.
  2. La instancia de entidad cargada se manipula de la manera habitual mediante la asignación de una propiedad .NET. EF no participa en este paso.
  3. Por último, se llama a DbContext.SaveChanges(). En este momento, EF detecta automáticamente los cambios comparando las entidades con una instantánea desde el momento en que se cargaron. Los cambios detectados se conservan en la base de datos; cuando se usa una base de datos relacional, esto normalmente implica el envío de un código SQL UPDATE para actualizar las filas pertinentes.

Tenga en cuenta que lo anterior describió una operación típica de actualización para los datos existentes, pero principios similares se aplican para agregar y quitar entidades. Interactúa con el rastreador de cambios de EF mediante una llamada a DbSet<TEntity>.Add y Remove, lo que hace que se realice el seguimiento de los cambios. A continuación, EF aplica todos los cambios registrados a la base de datos cuando se llama a SaveChanges() (por ejemplo, a través de SQL INSERT y DELETE cuando se usa una base de datos relacional).

SaveChanges() ofrece las siguientes ventajas:

  • No es necesario escribir código para realizar un seguimiento de las entidades y propiedades que han cambiado: EF lo hace automáticamente y solo actualiza esas propiedades en la base de datos, lo que mejora el rendimiento. Imagine si las entidades cargadas están enlazadas a un componente de interfaz de usuario, lo que permite a los usuarios cambiar cualquier propiedad que desee; EF quita la carga de averiguar qué entidades y propiedades se cambiaron realmente.
  • Guardar los cambios en la base de datos a veces puede ser complicado. Por ejemplo, si desea agregar un blog y algunas entradas para ese blog, es posible que tenga que capturar la clave generada por la base de datos para el blog insertado antes de poder insertar las entradas (ya que necesitan hacer referencia al blog). EF hace todo esto para usted, quitando la complejidad.
  • EF puede detectar problemas de simultaneidad, como cuando otra persona ha modificado una fila de base de datos entre la consulta y SaveChanges(). Más detalles disponibles en Conflictos de simultaneidad.
  • En las bases de datos que lo admiten, SaveChanges() ajusta automáticamente varios cambios en una transacción, lo que garantiza que los datos sean coherentes si se produce un error. Hay más detalles disponibles en Transacciones.
  • SaveChanges() también agrupa varios cambios en muchos casos, lo que reduce significativamente el número de recorridos de ida y vuelta de la base de datos y mejora considerablemente el rendimiento. Hay más detalles disponibles en Actualización eficaz.

Para obtener más información y ejemplos de código sobre el uso básico SaveChanges() , vea Basic SaveChanges. Para obtener más información sobre el seguimiento de cambios de EF, consulte la introducción al seguimiento de cambios.

Enfoque 2: ExecuteUpdate y ExecuteDelete ("actualización masiva")

Aunque el seguimiento de cambios y SaveChanges() son una manera eficaz de guardar los cambios, tienen ciertas desventajas.

En primer lugar, SaveChanges() requiere que consulte y realice un seguimiento de todas las entidades que va a modificar o eliminar. Si necesita, por ejemplo, eliminar todos los blogs con clasificación por debajo de un umbral determinado, debe consultar, materializar y realizar el seguimiento de un número quizá enorme de filas y que SaveChanges() genere una instrucción DELETE para cada una de ellas. Las bases de datos relacionales proporcionan una alternativa mucho más eficaz: se puede enviar un solo DELETE comando, especificando las filas que se van a eliminar a través de una WHERE cláusula, pero el SaveChanges() modelo no permite generarlo.

Para admitir este escenario de "actualización masiva", puede usar ExecuteDelete como se indica a continuación:

context.Blogs.Where(b => b.Rating < 3).ExecuteDelete();

Esto le permite expresar una instrucción SQL DELETE a través de operadores LINQ normales , similar a una consulta LINQ normal, lo que hace que se ejecute el siguiente CÓDIGO SQL en la base de datos:

DELETE FROM [b]
FROM [Blogs] AS [b]
WHERE [b].[Rating] < 3

Esto se ejecuta de forma muy eficaz en la base de datos, sin cargar ningún dato de la base de datos o que implique el seguimiento de cambios de EF. Del mismo modo, ExecuteUpdate permite expresar una instrucción SQL UPDATE .

Incluso si no cambia las entidades de forma masiva, es posible que sepa exactamente qué propiedades de la entidad desea cambiar. El uso de la API de seguimiento de cambios para realizar el cambio puede ser demasiado complejo, lo que requiere crear una instancia de entidad, seguirlo a través de Attach, hacer los cambios y, por último, llamar a la función SaveChanges(). Para estos escenarios, ExecuteUpdate y ExecuteDelete puede ser una manera considerablemente más sencilla de expresar la misma operación.

Por último, tanto el seguimiento de cambios como SaveChanges() el propio imponen alguna sobrecarga en tiempo de ejecución. Si está escribiendo una aplicación de alto rendimiento, ExecuteUpdate y ExecuteDelete le permiten evitar ambos componentes y generar eficazmente la instrucción que desee.

Sin embargo, tenga en cuenta que ExecuteUpdate y ExecuteDelete también tienen ciertas limitaciones:

  • Estos métodos se ejecutan inmediatamente y actualmente no se pueden procesar por lotes con otras operaciones. Por otro lado, SaveChanges(), puede procesar por lotes varias operaciones juntas.
  • Dado que el seguimiento de cambios no está implicado, es responsabilidad suya saber exactamente qué entidades y propiedades deben cambiarse. Esto puede significar un seguimiento de código más manual y de bajo nivel para determinar qué es lo que necesita cambiar y qué no.
  • Además, dado como no hay seguimiento de cambios, estos métodos no aplican automáticamente el control de simultaneidad al conservar los cambios. Sin embargo, puede agregar explícitamente una cláusula Where para implementar el control de simultaneidad usted mismo.
  • Actualmente solo se admiten la actualización y la eliminación; la inserción debe realizarse con DbSet<TEntity>.Add y SaveChanges().

Para obtener más información y ejemplos de código, vea ExecuteUpdate y ExecuteDelete.

Resumen

A continuación se muestran algunas directrices para cuándo usar el enfoque. Tenga en cuenta que estas no son reglas absolutas, pero proporcionan reglas útiles de control general:

  • Si no sabe con antelación qué cambios tendrán lugar, use SaveChanges; detectará automáticamente qué cambios se deben aplicar. Escenarios de ejemplo:
    • "Quiero cargar un blog desde la base de datos y mostrar un formulario que permita al usuario cambiarlo"
  • Si necesita manipular un gráfico de objetos (es decir, varios objetos interconectados), use SaveChanges; averiguará el orden adecuado de los cambios y cómo vincular todo juntos.
    • "Quiero actualizar un blog, cambiar algunas de sus publicaciones y eliminar otras"
  • Si desea cambiar un número potencialmente elevado de entidades en función de algún criterio, use ExecuteUpdate y ExecuteDelete. Escenarios de ejemplo:
    • "Quiero dar a todos los empleados un aumento"
    • "Quiero eliminar todos los blogs cuyo nombre comienza por X"
  • Si ya sabe exactamente qué entidades desea modificar y cómo desea cambiarlas, use ExecuteUpdate y ExecuteDelete. Escenarios de ejemplo:
    • "Quiero eliminar el blog cuyo nombre es "Foo"
    • "Quiero cambiar el nombre del blog con id. 5 a "Bar"