Software
20.08.2024 13:34

Compartir con otros:

Compartir

Mapeo relacional de objetos con Entity Framework

Hoy en día, la World Wide Web es el servicio más popular de la red informática más grande, Internet. Cada día se incorporan más de 100.000 nuevas páginas web, desde estáticas con un mínimo soporte de interacción hasta dinámicas que requieren una gran cantidad de datos actualizados para realizar sus funciones.
La foto es ilustrativa. (Foto: Pixabay)
La foto es ilustrativa. (Foto: Pixabay)

Autor: Denis Balant, Enej Hudobreznik


A pesar del rápido desarrollo de la tecnología, el lenguaje principal para gestionar bases de datos relacionales sigue siendo SQL o Lenguaje de consulta estructurado, que con muchos derivados personalizados (PostgreSQL, MySQL...) tiene sus raíces en los años 70 del siglo pasado.

Escribir consultas SQL a menudo resulta ser un trabajo que requiere bastante tiempo, especialmente con estructuras de bases de datos más complejas. En lugar de escribir manualmente consultas y conversiones a objetos típicos de los lenguajes de programación orientados a objetos, es mucho más natural y, a menudo, más sencillo asignar clases desde el código fuente al esquema de datos y no al revés. Esto ahorra tiempo de desarrollo y al mismo tiempo es mucho más fácil reconocer las relaciones entre entidades. Este método se llama mapeo relacional de objetos (ORM).

Para el entorno .NET, Microsoft ofrece el marco de código abierto Entity Framework Core (EF Core para abreviar), que permite el desarrollo orientado a datos (el enfoque Code First), donde los datos interconectados simplemente se recopilan en clases que representan tablas. y el marco se basa en ellos, comprende las relaciones y crea un esquema de base de datos en su propio formato. La mayor ventaja de este enfoque es la posibilidad de instalar el esquema de datos en la base de datos deseada sin conocer SQL.

EF Core se comunica con las bases de datos a través de bibliotecas de complementos llamadas proveedores de bases de datos, por lo que cambiar a otra base de datos es fácil. El usuario puede instalarlos a través del administrador de paquetes (NuGet para C#). Las bibliotecas oficiales sólo están disponibles para las soluciones SQL Server y Azure Cosmos DB de Microsoft y el proyecto SQLite, y gracias a la sólida comunidad de código abierto, el marco soporta prácticamente todas las principales bases de datos relacionales (MySQL, PostgreSQL...).

Como ejemplo de modelado de datos, echemos un vistazo a la tabla "Estudiante", que tiene los atributos nombre (cadena de hasta veinte caracteres), apellido (cadena de hasta veinte caracteres) e identificador único (entero).

Table Student (fuente propia)

En PostgreSQL, definimos esta tabla de la siguiente manera:

Definición de tabla de estudiantes en PostgreSQL (fuente propia)

Además de las definiciones de los tipos básicos de nombre y apellido, también requerimos que nunca estén vacíos (NO NULL). El tipo SERIAL representa un número entero único, que en nuestro caso sirve como clave principal del Id. Para cada entidad agregada, se determina automáticamente en función del ID de la identidad agregada anteriormente, que simplemente se incrementa.

Sin embargo, es mucho más fácil definir la tabla como una clase en el código fuente de la lógica de la aplicación utilizando un ORM que crea por sí mismo el objeto y los requisitos de la base de datos correspondientes. La etiqueta Clave encima del atributo de clase indica la clave principal y Requerido indica que el atributo no debe estar vacío.

Después del desarrollo, el marco EF Core nos permite generar automáticamente un esquema de datos a partir del código e implementarlo en la base de datos seleccionada a través de las herramientas de línea de comandos que se incluyen en el marco. Los cambios graduales en el esquema de la base de datos se gestionan a través de estas migraciones, que garantizan que la base de datos permanezca sincronizada con el modelo de datos de la aplicación. Las nuevas migraciones, que se almacenan en EF Core en forma de clases especiales, se crean comparando el modelo de datos actual con el esquema de base de datos actual (estado de la última migración).

Definición de tabla de estudiantes usando EF Core en entorno .NET (fuente propia)

La conexión de la base de datos es abstraída por una clase que hereda de la clase DbContext. Sus atributos son colecciones de entidades de tipo DbSet que se asignan a tablas.

Clase de conexión de base de datos y tabla de estudiantes definida (fuente propia)

El marco mencionado anteriormente para escribir consultas utiliza la sintaxis LINQ, que representa una forma unificada de recuperar y procesar datos de diferentes fuentes. Luego, la consulta se traduce a SQL y el resultado en sí se vuelve a traducir a un objeto, su atributo o una tabla de objetos.

El siguiente ejemplo muestra una consulta para un estudiante con un número de inscripción conocido. Basta con una sola llamada al método Find con el valor de la clave principal (ID).

Ejemplo de consulta de estudiante con EF Core (fuente propia)

Si queremos lograr el mismo resultado sin utilizar una herramienta ORM, se requiere mucho más código. Se muestra un ejemplo utilizando la biblioteca NpgSql. Primero, necesitamos crear objetos que representen la consulta SQL y leer la base de datos, mientras que debemos tener cuidado de incluir el parámetro correctamente para evitar posibles vulnerabilidades, como por ejemplo. Inyección SQL. Esta vez tenemos que crear el objeto de estudiante nosotros mismos, pero debemos tener cuidado con el orden de los atributos en la consulta y la posibilidad de que se produzca un error en la consulta.

Ejemplo de consulta de estudiante usando la biblioteca NpgSql (fuente propia)
Respuesta a la consulta anterior (fuente propia)

El mapeo relacional de objetos nos ofrece así una capa de abstracción que acelera significativamente el desarrollo de software debido a su mapeo desde un plan de desarrollo orientado a objetos, porque el código SQL no necesita escribirse por separado del código fuente (a menudo orientado a objetos). Un ORM bien escrito admite buenos patrones y prácticas de desarrollo para el diseño de aplicaciones, al tiempo que permite a los desarrolladores que no utilizan SQL integrar más fácilmente una base de datos relacional en su aplicación.

Sin embargo, es importante enfatizar que ORM no es una solución perfecta. La debilidad radica precisamente en la abstracción que nos ofrece. Genera significativamente más código SQL del que escribiría un desarrollador, lo que puede afectar en gran medida la velocidad de la aplicación, puede ocultar malas prácticas de acceso a la base de datos y es un problema de compatibilidad con versiones anteriores. Aunque el código generado es correcto en la mayoría de los casos, se recomienda verificarlo y probarlo manualmente.

El mapeo relacional de objetos es una funcionalidad que no es nativa del entorno .NET. La mayoría de los marcos y bibliotecas proporcionan funcionalidad para diferentes idiomas. Algunos ejemplos son Django para Python, Gorm para Go, Spring para Java, Prisma para JavaScript (o Node.js)...




¿Qué están leyendo los demás?