Bienvenidos nuevamente.
Si estás en este post, significa que ya completaste la primera parte de esta guía, donde preparamos la base para nuestro proyecto con Entity Framework. Ahora, es momento de continuar exactamente donde lo dejamos, profundizando en los siguientes pasos clave:
Si mantenemos ambas, corremos el riesgo de inconsistencias: un valor de CodigoCat podría no coincidir con la entidad referenciada en Categoria. Para evitar confusiones y garantizar que las relaciones sean claras y consistentes, eliminamos las redundancias y trabajamos solo con las propiedades necesarias según nuestro caso de uso.
Esto mantiene el modelo más limpio, fácil de entender y menos propenso a errores cuando manejemos los estados de las entidades o entities.
Click derecho encima de la propiedad de navegación Artículo de la entidad Categoría y procedemos a Eliminar del modelo. La entidad cliente, no sufre cambios.
El modelo debería quedar algo así:En este proyecto de consola, que simulará la "interfaz de usuario" (UI) desde donde el cliente o usuario consumirá nuestro servicio, vamos a crear las operaciones necesarias para empezar a trabajar con ejemplos en Entity Framework.
Antes de avanzar con esto, es fundamental instalar Entity Framework también en este proyecto de consola y además importar la cadena de conexión para la base de datos. Para hacerlo, esta vez utilizaremos la terminal o la consola del Administrador de paquetes.
Vamos a hacer click derecho sobre la solución ➜ Agregar ➜ Nuevo Proyecto y vamos a buscar y seleccionar Consola .NET Framework.
Con esto, nuestros requerimientos estarían cubiertos.. al menos por ahora.
Si estás en este post, significa que ya completaste la primera parte de esta guía, donde preparamos la base para nuestro proyecto con Entity Framework. Ahora, es momento de continuar exactamente donde lo dejamos, profundizando en los siguientes pasos clave:
- Eliminar redundancias del modelo para optimizar nuestra estructura de datos.
- Crear el proyecto de consola, donde conectaremos nuestro modelo con el código funcional.
- Instalar y configurar Entity Framework, asegurándonos de tener todo listo para interactuar con nuestra base de datos.
💡 Si todavía no viste la primera parte, te recomiendo revisarla para estar al día:
1. Eliminar redundancias del modelo
En el modelo .edmx, las redundancias ocurren cuando una propiedad aparece duplicada como una FK y como una propiedad de navegación. Por ejemplo, en la entidad Articulo, tenemos tanto la propiedad CodigoCat (FK) como la propiedad de navegación Categoria.Si mantenemos ambas, corremos el riesgo de inconsistencias: un valor de CodigoCat podría no coincidir con la entidad referenciada en Categoria. Para evitar confusiones y garantizar que las relaciones sean claras y consistentes, eliminamos las redundancias y trabajamos solo con las propiedades necesarias según nuestro caso de uso.
Esto mantiene el modelo más limpio, fácil de entender y menos propenso a errores cuando manejemos los estados de las entidades o entities.
El modelo debería quedar algo así:
Llegado a este punto, vamos a recompilar la solución para asegurarnos de que no tengamos errores. Click derecho sobre la Solución ➜ Recompilar solución.
2. Creando el proyecto de consola
Antes de avanzar con esto, es fundamental instalar Entity Framework también en este proyecto de consola y además importar la cadena de conexión para la base de datos. Para hacerlo, esta vez utilizaremos la terminal o la consola del Administrador de paquetes.
Vamos a hacer click derecho sobre la solución ➜ Agregar ➜ Nuevo Proyecto y vamos a buscar y seleccionar Consola .NET Framework.
Nombramos el proyecto y nos cercioramos de tener marcada la versión correcta del marco de trabajo.
Ahora vamos a referenciar el proyecto para que "vea" o se pueda comunicar con el modelo.
Para ello tenemos que hacer click derecho en Referencias del proyecto de consola ➜ Agregar referencia
Seleccionamos el Modelo en la siguiente ventana y damos click en aceptar.
3. Instalación de EF mediante CLI
Para instalar Entity Framework por terminal, vamos a ir a Herramientas ➜ Administrador de paquetes NuGet ➜ Consola del Administrador de paquetes
En la parte inferior de la solución se abrirá la terminal donde lo primero que tenemos que hacer es seleccionar el proyecto donde queremos instalar el paquete. Asegurate de que esté seleccionado el proyecto de consola que hicimos anteriormente.
Ejecutamos el comando en el prompt:
- Install-Package EntityFramework
Si todo finalizó correctamente deberías de ver un mensaje de éxito:
4. Copiar cadena de conexión
Esta información se encuentra en el archivo App.config del modelo, por lo que vamos a abrir el archivo desde ahí y a copiar este bloque de texto, dejo un ejemplo pero el de tu proyecto puede variar por lo que vas a tener que copiarlo desde tu archivo:
<connectionStrings>
<add name="Blog_EF01Entities" connectionString="metadata=res://*/EjemploEF.csdl|res://*/EjemploEF.ssdl|res://*/EjemploEF.msl;provider=System.Data.SqlClient;provider connection string="data source=.;initial catalog=Blog_EF01;integrated security=True;encrypt=True;trustservercertificate=True;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
</connectionStrings>
Una vez copiado, lo pegamos antes de la etiqueta de cierre </configuration> del archivo App.config de nuestro proyecto de consola. Asegurate de copiar todo el contenido (incluido las etiquetas de apertura y cierre) que se comprende entre los tags de <connectionStrings> ... </connectionStrings>
Debería verse algo similar a esto:
Establecer el proyecto de inicio
Por último, lo que nos falta es establecer como proyecto de inicio ese mismo proyecto de consola. De esta forma, cuando ejecutemos nuestra solución se iniciará nuestro código de consola.
En el explorador de soluciones damos click derecho sobre el proyecto ➜ Establecer como proyecto de inicio
Con esto, en teoría, ya podríamos ponernos a picar un poco de código (al fin..)
5. Codificando las operaciones
Lo primero que necesitamos es importar o agregar el modelo a nuestro proyecto de consola con el using correspondiente:
- using Modelo;
A partir de ahí podemos desarrollar nuestro requerimiento de la manera que más nos convenga, aunque para este ejemplo vamos a agregar algunas validaciones de forma manual.
Si corroboramos el apartado del Modelo, las clases (o entidades) fueron creadas automáticamente por el ORM, y ese archivo no puede modificarse.
Este diseño difiere del modelo de capas donde tenemos una biblioteca de clases para las entidades programada por nosotros manualmente.
Validaciones del modelo
Vamos a crear un nuevo directorio en el modelo y lo vamos a nombrar "Util" haciendo click derecho en el proyecto ➜ Agregar ➜ Nueva Carpeta
En esa carpeta, vamos a crear una nueva clase click derecho sobre la nueva carpeta ➜ Agregar ➜ Clase y la vamos a llamar ValidarArticulo.cs
Esta clase va a contener nuestras validaciones, para el ejemplo son solo algunas validaciones básicas con Regex. Hace click acá si querés profundizar en este tema un poco más.
Mi recomendación sería que intentes escribir la clase por tu cuenta. Esto te va a ayudar a fortalecer la mecánica de la escritura de código y a desarrollar tu memoria muscular, que es clave para consolidar lo que aprendés. Sin embargo, si llevas prisa o querés verificar tus resultados, acá te dejo la solución para que la uses como referencia:
using System;
using System.Text.RegularExpressions;
namespace Modelo.Util
{
public static class ValidarArticulo
{
/// <summary>
/// Valida una entidad de tipo Artículo.
/// </summary>
/// <param name="articulo"> el objeto artículo a validar</param>
/// <returns>true si pasa las validaciones, de lo contrario false</returns>
public static bool Validar(Articulo articulo)
{
// 1. Código
if(!Regex.IsMatch(articulo.CodigoArt, @"^[a-zA-Z0-9]{10}$"))
{
Console.WriteLine($"El código {articulo.CodigoArt} no es válido.");
return false;
}
// 2. Descripción
if (!Regex.IsMatch(articulo.Descripcion, @"^.{3,40}$"))
{
Console.WriteLine($"La descripción del artículo debe contener entre 3 y 40 carácteres.");
return false;
}
// 3. Precio
if (articulo.Precio <= 0)
{
Console.WriteLine($"Debe especificar un precio mayor a cero.");
return false;
}
// 4. FchIngreso
if (articulo.FchIngreso == default(DateTime))
{
Console.WriteLine($"La fecha del artículo no es válida.");
return false;
}
// 5. Categoría
if (articulo.Categoria == null)
{
Console.WriteLine($"La categoría no puede ser nula.");
return false;
}
return true;
}
}
}
¿Cómo funciona la validación?
Brevemente, se recibe un objeto Articulo como parámetro. y se valida cada propiedad del objeto de forma independiente según las reglas específicas. En caso de que alguna validación falle se muestra un mensaje de error en la consola y el método devuelve un bool en falso. En caso de que todas las validaciones sean exitosas el método retorna verdadero.
Ahora que podemos validar nuestro objeto Artículo podemos crear una operación con EF para agregar un nuevo artículo a la base de datos. Pero antes, vamos a recorrer la tabla desde el programa para ver los registros que existen previa a las alteraciones que hagamos en la base.
Consultando la tabla Artículo
En el proyecto de consola, vamos a abrir nuestra clase Program.cs y vamos a importar nuestro modelo y el nombre de espacio "Util" para las validaciones:
- using Modelo;
- using Modelo.Util;
A continuación, en el cuerpo del método principal vamos a declarar e inicializar el contexto de nuestro Modelo de datos y a crear una List<Articulo> de artículos para luego recorrerla y leerla desde la consola:
static void Main(string[] args)
{
// 1. Declaramos e inicializamos el contexto
Blog_EF01Entities context = new Blog_EF01Entities();
// 2. Creamos una lista para recuperar los artículos y la recorremos
// con un foreach
List<Articulo> articulos = context.Articulo.ToList();
foreach (var articulo in articulos)
{
Console.WriteLine($"Código: {articulo.CodigoArt}, Descripción: {articulo.Descripcion}");
}
Console.ReadLine();
}
Presiona F5 desde el teclado o dale al botón de Play en verde en la barra superior del VS y verificá los resultados. Deberías tener una salida como la que te muestro en la imagen:Con este ejemplo, vimos cómo, en 4 o 5 líneas de código, nos conectamos a la base de datos, recuperamos todos los registros de la tabla Articulos y los mostramos en pantalla, sin necesidad de escribir ni una sola query. Pero esto es solo el comienzo porque con LINQ, podés llevar este enfoque mucho más allá, aplicando filtros, ordenamientos y consultas específicas de manera fluida y expresiva, lo que simplifica enormemente el trabajo con los datos en nuestra aplicación.
Agregar un artículo
Como se mostró en la clase generada para la entidad y en le diagrama .edmx del modelo, la entidad Artículo está compuesto por varios atributos, uno de ellos es un objeto Categoría. Eso quiere decir que para crear un nuevo artículo, necesitamos una categoría existente porque tenemos una integridad referencial que fue definida a nivel de bases de datos.
Acá vamos a usar una consulta con LINQ para recuperar la categoría Útiles Escolares con código ESC123 de la siguiente forma:
// Recuperar un objeto de la tabla Categoria para añadir un artículo nuevo
Categoria categoria
= context.Categoria
.Where(c => c.CodigoCat.Equals("ESC123"))
.FirstOrDefault();
Ya tenemos un objeto categoría para nuestro insert.
Para crear el nuevo artículo simplemente instanciamos un nuevo objeto con el operador new y asignamos valor a sus propiedades. Recordemos que con el new operator generamos una nueva instancia en memoria de un objeto. En nuestro ejemplo, un objeto Artículo.
// Creamos el nuevo artículo
Articulo nuevoArticulo = new Articulo
{
CodigoArt = "JGOGEO0001",
Descripcion = "Juego de geometría escolar.",
Precio = 150.00m,
FchIngreso = DateTime.Now,
Categoria = categoria
};
Le aplicamos el control de las validaciones:
// Validación del nuevo objeto
// Invocamos la clase validar artículo desde Util
bool esValido = ValidarArticulo.Validar(nuevoArticulo);
// Busco el código del artículo nuevo en la tabla
Articulo buscoArticuloRepetido
= context.Articulo
.Where(a => a.CodigoArt.ToLower()
.Equals(nuevoArticulo.CodigoArt.ToLower()))
.FirstOrDefault();
// Falló en las validaciones, se ingresó algún dato incorrecto
if (!esValido)
{
Console.WriteLine($"Las propiedades del artículo no son válidas.");
return;
}
// Artículo repetido, buscoArticuloRepetido no es nulo
if (buscoArticuloRepetido != null)
{
Console.WriteLine($"El artículo con código {nuevoArticulo.CodigoArt} ya se encuentra registrado.");
return;
}
Si todo salió bien, lo añadimos al contexto y lo salvamos a la base de datos:
// Llegamos hasta acá, todo salió bien
// Agregamos el nuevo artículo al contexto, pero aún no se refleja en la base de datos
context.Articulo.Add(nuevoArticulo);
// Confirmamos el insert en la base de datos con SaveChanges()
// Este método guarda los cambios pendientes en el contexto
context.SaveChanges();
// Brindamos un mensaje de éxito al usuario
Console.WriteLine($"El artículo con código {nuevoArticulo.CodigoArt} fue agregado a la base de datos.");
Si volvemos a ejecutar la aplicación vamos a ver listado el nuevo artículo que acabamos de ingresar, pero la verdadera prueba o la "prueba de fuego" para creernos todo esto del ORM, es que vayamos a la base de datos y ejecutemos una consulta a la tabla Artículos desde ahí:
SELECT * FROM [Blog_EF01].[dbo].[Articulo]
WHERE CodigoArt='JGOGEO0001';
Supongamos que ahora necesitamos modificar un artículo y, para nuestra sorpresa, un usuario parece haber ingresado un artículo en una categoría incorrecta (no sé si te diste cuenta, pero en la captura del listado se veía un smarthphone en la categoría cocina, no podemos dejar eso así).
Para corregir ese pequeño gran error vamos a hacer lo siguiente:
// Modificar artículo
Articulo articuloMalIngresado
= context.Articulo.Where(a => a.CodigoArt
.Equals("K000000011"))
.FirstOrDefault();
// Necesitamos el objeto categoria 'TECH25' para la actualización
Categoria categoriaTech
= context.Categoria
.Where(c => c.CodigoCat.Equals("TECH25"))
.FirstOrDefault();
if (articuloMalIngresado != null && categoriaTech != null)
{
// Usamos las propiedades de navegación para modificar la categoría
articuloMalIngresado.Categoria = categoriaTech;
// Salvamos los cambios que hicimos en el contexto para el update en la base de datos
context.SaveChanges();
// Brindamos un mensaje de éxito
Console.WriteLine($"El artículo con código {articuloMalIngresado.CodigoArt} fue actualizado con éxito.");
}
Corroboramos que las modificaciones impactaron en la base de datos:
SELECT * FROM [Blog_EF01].[dbo].[Articulo]
Eliminar un Artículo
Nos quedaría una operación más para ver, dentro de lo que serían operaciones comúnmente utilizadas en un CRUD, el Remove() de Entity Framework.
Para este caso, vamos a simular que el lote de artículos misceláneos nunca debería haber ingresado al sistema sino que alguien lo cargó por error. ¡Estos usuarios!
Vamos a utilizar la función RemoveRange() de EF de esta manera:
// 12. Eliminar todos los artículos con categoría "MIS789"
// Para esto vamos a usar RemoveRange para los artículos que tienen esa categoría
context.Articulo.RemoveRange(context.Articulo
.Where(a => a.Categoria.CodigoCat
.Equals("MIS789")));
// Salvamos los cambios que hicimos en el contexto para el delete en la base de datos
context.SaveChanges();
// Brindamos un mensaje de éxito
Console.WriteLine($"Los artículos con categoria 'MIS789' fueron eliminados con éxito.");
Corroboramos en la base de datos:
Reconozco que quedó cargado este artículo, pero me pareció interesante crear esta guía ya que a partir de acá la podés amoldar a tus requerimientos implementando Entity Framework.
Más o menos, creo que con esta información, podrías realizar varias prácticas como por ejemplo:
- Repasar los conceptos con la entidad Cliente.
- Crear un CRUD con Entity Framework.
- Extender la funcionalidad ampliando la base de datos, agregar una tabla de ventas con sus facturas y relaciones.
- Crear una Minimal API con .NET Core, que es super intuitivo y divertido.
En fin, las posibilidades son tan amplias como las puedas imaginar.
Recordá que te dejo esta solución, con todo lo que vimos, en un repositorio de Github:
En el readme tenés las instrucciones para clonar el proyecto y ejecutar la solución en Visual Studio con .NET Framework.
Si querés, podés darme un follow por ahí que sería de gran ayuda, además de que estoy trabajando en proyectos con .NET Core y Angular que te pueden llegar a interesar y así te mantenés en contacto.
Valar Morghulis