Ir al contenido principal

Creando un Proyecto con Entity Framework - Parte 2

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:
  • 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.
 

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í:
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

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.



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 NuGetConsola 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=&quot;data source=.;initial catalog=Blog_EF01;integrated security=True;encrypt=True;trustservercertificate=True;MultipleActiveResultSets=True;App=EntityFramework&quot;" 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';

Modificar un Artículo

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:


Con esto, nuestros requerimientos estarían cubiertos.. al menos por ahora.



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

Otros artículos

Principio de Responsabilidad Única (SRP) – SOLID explicado con ejemplos

Introducción a S.O.L.I.D En esta entrada, intentaremos abordar un nuevo ciclo de conceptos que tienen que ver sobre los principios SOLID , que son fundamentales en la programación orientada a objetos o POO . Estos principios fueron formulados, en principio, por Robert C. Martin , también conocido como " Uncle Bob ", con el objetivo de mejorar la mantenibilidad y escalabilidad del código de software. SOLID es un acrónimo que representa cinco principios de diseño: Single Responsibility Principle (SRP) – Principio de Responsabilidad Única Open/Closed Principle (OCP) – Principio de Abierto/Cerrado Liskov Substitution Principle (LSP ) – Principio de Sustitución de Liskov Interface Segregation Principle (ISP) – Principio de Segregación de Interfaces Dependency Inversion Principle (DIP) – Principio de Inversión de Dependencias Estos principios nos ayudan a crear software más ...

Open/Closed Principle (OCP) – SOLID explicado con ejemplos

Continuando con el repaso de los principios de S.O.L.I.D. que inició en el hilo anterior - si no lo viste hacé click acá  Principio de Responsabilidad Única (SRP) - vamos a ver el segundo en orden de aparición: Principio de Abierto/Cerrado (OCP por sus siglas en inglés). Definición Formal El principio OCP (Open/Closed Principle) establece que el código de una clase o un módulo debe estar abierto para la extensión, pero cerrado para la modificación. Esto significa que no se deben realizar cambios en el código existente cuando se requiere alterar alguna funcionalidad. En lugar de modificar el código existente, se debe crear una nueva implementación que extienda la funcionalidad. La única excepción a esto son los arreglos de bugs, donde está permitido modificar el código existente. Si se desea introducir una nueva funcionalidad, como la ordenación en un método existente, en lugar de modificar el código, se crearía una nueva implementación q...

Roadmap para Desarrolladores Backend en .NET en 2025

El mundo del desarrollo backend está en constante evolución, y mantenerse actualizado con las mejores prácticas y tecnologías es clave para seguir siendo competitivo en el mercado. Si estás buscando una guía clara y estructurada para mejorar tus habilidades en . NET backend , el sitio roadmap.sh ofrece un excelente punto de partida. Para esta entrada vamos a explorar lo siguiente: ¿Qué es roadmap.sh y por qué es relevante? El roadmap backend para .NET en 2025 Tecnologías y habilidades esenciales para backend a considerar ¿Qué es roadmap.sh y quién lo creó? roadmap.sh es una plataforma ampliamente reconocida dentro de la comunidad de desarrolladores. Fue creada por Kamran Ahmed, un Google Developer Expert y contribuidor en múltiples proyectos de código abierto. Desde su lanzamiento, la plataforma ha crecido exponencialmente, acumulando más de 300,000 estrellas en GitHub y una comunidad activa de...

Codewars

Como algunos ya saben, soy un gran entusiasta de las plataformas en línea dedicadas a la educación y al entrenamiento de habilidades, lo que podríamos llamar "gimnasios mentales". Hoy quiero presentarles, o tal vez recordarles, una de mis favoritas: Codewars, conocida también como " Guerras de Código " en español. Si aún no la conocían, los invito a explorarla. Y si ya la conocían, este es un buen momento para redescubrirla y sacarle más provecho. ¿Qué es Codewars? Codewars es una plataforma educativa en línea diseñada como un juego para entrenar habilitades de programación. fue fundada en noviembre de 2012 por Nathan Doctor y Jake Hoffner . La idea surgió durante una competencia de Startup Weekend ese mismo año, donde desarrollaron un prototipo que obtuvo el primer lugar. En la actualidad, Codewars es propiedad de Qualified , una empresa tecnológica que ofrece una plataforma para evaluar y entrenar habilidades en ingeniería de software. Con esta herramienta pod...

Principio de Sustitución de Liskov (LSP) – SOLID explicado con ejemplos

¿Qué es el Principio de Sustitución de Liskov? Imaginá que tenés un control remoto universal diseñado para funcionar con cualquier televisor. Si un nuevo modelo de TV no responde a los mismos comandos, el control deja de ser útil. El Principio de Sustitución de Liskov es como una garantía de que cualquier 'televisor' (o clase derivada) va a funcionar correctamente con el 'control remoto' (o clase base). El Principio de Sustitución de Liskov ( LSP ) es el tercer principio de SOLID , representado por la letra L y establece que: Los objetos de una clase derivada deben poder sustituir a los objetos de su clase base sin afectar el comportamiento correcto del programa. En otras palabras, si una clase hija hereda de una clase padre, cualquier instancia de la clase hija debería poder usarse en lugar de una instancia de la clase padre sin alterar la funcionalidad esperada. ¿Quién es Bárbara Liskov? Bárbara Liskov es una destacada científi...

Principio de Segregación de Interfaces (ISP) – SOLID explicado con ejemplos

El Principio de Segregación de Interfaces es otro de los principios SOLID y establece que: Una clase no debería verse obligada a depender de métodos que no utiliza .  En otras palabras, en lugar de crear una interfaz grande con muchos métodos, es mejor dividirla (segregar) en interfaces más pequeñas y específicas. Pero.. ¿Por qué? Obliga a implementar métodos innecesarios Si una clase solo necesita una "parte" de la funcionalidad de una interfaz, pero esta interfaz es muy grande, se va a ver obligada a implementar métodos que no usa. Esto es casi que inevitable si no buscamos la manera de separar mejor las responsabilidades. Imaginemos una interfaz IVehiculo que tiene los siguientes métodos: public interface IVehiculo { void Conducir () ; void Volar () ; void Navegar () ; } Si una clase Auto implementa esta interfaz, se ve obligado a definir métodos como Volar() o Navegar() , aunque un auto no vuela ni navega. public c...
Buy Me A Coffee