Menú de navegaciónMenú
Categorías

La mejor forma de Aprender Programación online y en español www.campusmvp.es

¿Qué es un ORM?

Tradicionalmente, para realizar acceso a datos desde un lenguaje orientado a objetos (POO) como pueden ser .NET o Java, era necesario mezclar código y conceptos muy diferentes.

Por un lado teníamos la aplicación en sí, escrita en alguno de estos lenguajes como C# o Java. Dentro de éste programa hacíamos uso de ciertos objetos especializados en conectarse con bases de datos y lanzar consultas contra ellas. Estos objetos de tipo Connection, Query y similares, eran en realidad conceptos de la base de datos llevados a un programa orientado a objetos que no tenía nada que ver con ellos. Finalmente, para lanzar consultas (tanto de obtención de datos como de modificación o de gestión) se introducían instrucciones en lenguaje SQL, en forma de cadenas de texto, a través de estos objetos.

Además estaba el problema de los tipos de datos. Generalmente el modo de representarlos y sus nombres pueden variar entre la plataforma de desarrollo y la base de datos. Por ejemplo, en .NET un tipo de datos que almacena texto es simplemente un string. En SQL Server para lo mismo podemos utilizar cadenas de longitud fija o variable, de tipo Unicode o ANSI, etc... Y lo mismo con los otros tipos de datos. Algunos ni siquiera tienen por qué existir en el lenguaje de programación. Y tampoco debemos olvidarnos de los valores nulos en la base de datos, que pueden causar todo tipo de problemas según el soporte que tengan en el lenguaje de programación con el que nos conectamos a la base de datos.

Otros posibles problemas y diferencias surgen del modo de pensar que tenemos en un lenguaje orientado a objetos y una base de datos. En POO, por ejemplo, para representar una factura y sus líneas de factura podrías definir un objeto Factura con una propiedad Lineas, y si quieres consultar las líneas de una factura solo debes escribir factura.Lineas y listo, sin pensar en cómo se relacionan o de dónde sale esa información. En una base de datos, sin embargo, esto se modela con dos tablas diferentes, una para las facturas y otra para las líneas, además de ciertos índices y claves externas entre ellas que relacionan la información. Si además se diese el caso de que una misma línea de factura pudiese pertenecer a más de una factura, necesitas una tercera tabla intermedia que se relaciona con las dos anteriores y que hace posible localizar la información. Como vemos formas completamente diferentes de pensar sobre lo mismo.

La complejidad no termina aquí ya que las bases de datos tienen procedimientos almacenados (que son como pequeños programas especializados que se ejecutan dentro de la base de datos), transacciones, y otros conceptos que desde el punto de vista de un lenguaje POO son completamente extraterrestres y ajenos.

Estas diferencias entre conceptos, tipos de datos, y modos de trabajar pueden causar muchos problemas de lo que se dio en llamar "desfase de impedancia" o "impedance mismatch" en inglés, en una clara analogía los circuitos eléctricos y al flujo eléctrico (en este caso aplicado a flujo de información). El concepto se refiere a la dificultad para hacer fluir la información entre la base de datos y las diferentes capas del programa en función de la diferencia existente entre cada una de estas partes.

Este desfase de impedancia hace que pueda llegar a ser muy complicado trabajar contra una base de datos desde un lenguaje POO si queremos sacar partido a los conceptos habituales que usamos en éstos, y huir de bibliotecas de funciones que nos fuerzan a trabajar con los conceptos de la base de datos.

"Mapeadores" al rescate

Imagen ornamental

Como acabamos de ver, lo ideal en una aplicación escrita en un lenguaje orientado a objetos sería definir una serie de clases, propiedades de éstas que hagan referencia a las otras, y trabajar de modo natural con ellas.

¿Qué quieres una factura? Simplemente instancias un objeto Factura pasándole su número de factura al constructor. ¿Necesitas sus líneas de detalle? LLamas a la propiedad Lineas del objeto. ¿Quieres ver los datos de un producto que está en una de esas líneas? Solo lee la propiedad correspondiente y tendrás la información a tu alcance. Nada de consultas, nada de relaciones, de claves foráneas...

En definitiva nada de conceptos "extraños" de bases de datos en tu código orientado a objetos. En la práctica para ti la base de datos es como si no existiera.

Eso precisamente es lo que intenta conseguir el software llamado ORM, del inglés Object-Relational Mapper o "Mapeador" de relacional a objetos (y viceversa). Un ORM es una biblioteca especializada en acceso a datos que genera por ti todo lo necesario para conseguir esa abstracción de la que hemos hablado.

Gracias a un ORM ya no necesitas utilizar SQL nunca más, ni pensar en tablas ni en claves foráneas. Sigues pensando en objetos como hasta ahora, y te olvidas de lo que hay que hacer "por debajo" para obtenerlos.

El ORM puede generar clases a partir de las tablas de una base de datos y sus relaciones, o hacer justo lo contrario: partiendo de una jerarquía de clases crear de manera transparente las entidades necesarias en una base de datos, ocupándose de todo (ni tendrás que tocar el gestor de bases de datos para nada).

¿Qué ORMs tenemos disponibles?

  • En el mundo Java el ORM más conocido y utilizado es Hibernate que pertenece a Red Hat aunque es gratuito y Open Source. Hay muchos otros como Jooq, ActiveJDBC que trata de emular los Active Records de Ruby On Rails, o QueryDSL, pero en realidad ninguno llega ni por asomo al nivel de uso de Hibernate. Si necesitas un ORM en Java debes aprender Hibernate, y luego ya si quieres te metes con otro, pero este es indispensable.

  • En la plataforma .NET tenemos varios conocidos, pero el más popular y utilizado es Entity Framework o EF, que es el creado por la propia Microsoft y que viene incluido en la plataforma .NET (tanto en la "tradicional" como en .NET Core). También existe un "port" de Hibernate para .NET llamado NHibernate y que a mucha gente le gusta más que EF. Hay otros como Dapper que está creado por la gente de Stack Exchange y es mucho más sencillo que los anteriores, lo cual es considerado una gran virtud por mucha gente (entre los que me incluyo), y también es muy utilizado. Y es muy conocido Subsonic, que lleva casi diez años en activo pero que puede llegar a ser bastante complicado (a mí personalmente no me gusta nada).

En PHP tienes Doctrine, tal vez el más conocido y recomendado (utilizado por el framework Symfony), pero también se usan bastante Propel, RedbeanPHP y uno muy popular pero ya en desuso es Xyster (pero te lo encontrarás aún bastante por ahí).

En Python el híper-conocido framework Django (así sinónimo de desarrollo web con este lenguaje) incluye su propio ORM, pero también tenemos SQLAlchemy por el que muchos beben los vientos y lo califican como el mejor ORM jamás hecho (no tengo experiencia con él como para saberlo). También están Peewee o Pony ORM entre otros.

Prácticamente todas las plataformas tienen el suyo, así que búscalos para la tuya y mira cuál es el más popular y el que más comunidad reúne.

Ventajas e inconvenientes de un ORM

Los ORM ofrecen enormes ventajas, como ya hemos visto, al reducir esa "impedancia" que impide el buen flujo de información entre los dos paradigmas POO-Relacional. Pero además:

  • No tienes que escribir código SQL, algo que muchos programadores no dominan y que es bastante complejo y propenso a errores. Ya lo hacen por nosotros los ORM.
  • Te dejan sacar partido a las bondades de la programación orientada a objetos, incluyendo por supuesto la herencia, lo cual da mucho juego para hacer cosas.
  • Nos permiten aumentar la reutilización del código y mejorar el mantenimiento del mismo, ya que tenemos un único modelo en un único lugar, que podemos reutilizar en toda la aplicación, y sin mezclar consultas con código o mantener sincronizados los cambios de la base de datos con el modelo y viceversa.
  • Mayor seguridad, ya que se ocupan automáticamente de higienizar los datos que llegan, evitando posibles ataques de inyección SQL y similares.
  • Hacen muchas cosas por nosotros: desde el acceso a los datos (lo obvio), hasta la conversión de tipos o la internacionalización del modelo de datos.

Pero no todo va a ser alegría. También tienen sus inconvenientes:

  • Para empezar pueden llegar a ser muy complejos. Por ejemplo, NHibernate tiene ya más de medio millón de líneas de código ahora mismo, y muchas clases y detalles que hay que saber. Eso hace que su aprendizaje sea complejo en muchos casos, y hay que invertir tiempo en aprenderlos y practicar con ellos hasta tener seguridad en su manejo diario.
  • No son ligeros por regla general: añaden una capa de complejidad a la aplicación que puede hacer que empeore su rendimiento, especialmente si no los dominas a fondo. En la mayor parte de las aplicaciones probablemente no te importe, pero en ocasiones su impacto en el rendimiento es algo a tener muy en cuenta. En general una consulta SQL directa será más eficiente siempre.
  • La configuración inicial que requieren se puede complicar dependiendo de la cantidad de entidades que se manejen y su complejidad, del gestor de datos subyacente, etc...
  • El hecho de que te aísle de la base de datos y no tengas casi ni que pensar en ella es un arma de doble filo. Si no sabes bien lo que estás haciendo y las implicaciones que tiene en el modelo relacional puedes construir modelos que generen consultas monstruosas y muy poco óptimas contra la base de datos, agravando el problema del rendimiento y la eficiencia.

En definitiva, los ORM son una herramienta que puede llegar a ser maravillosa, pero que en aplicaciones pequeñas pueden ser como "matar moscas a cañonazos". En aplicaciones más grandes donde el mantenimiento y la homogeneidad sean importantes, son indispensables. Eso sí, no te eximen de aprender bien el lenguaje SQL o las maneras más tradicionales de realizar acceso a datos, ya que conocerlas puede marcar la diferencia cuando surjan problemas o haya que determinar por qué se produce una merma de rendimiento, etc...

José M. Alarcón Aguín Fundador de campusMVP, es ingeniero industrial y especialista en consultoría de empresa. Ha escrito diversos libros, habiendo publicado hasta la fecha cientos de artículos sobre informática e ingeniería en publicaciones especializadas. Microsoft lo ha reconocido como MVP (Most Valuable Professional) en desarrollo web desde el año 2004 hasta la actualidad. Puedes seguirlo en Twitter en @jm_alarcon o leer sus blog técnico o personal. Ver todos los posts de José M. Alarcón Aguín
Archivado en: Acceso a Datos

Boletín campusMVP.es

Solo cosas útiles. Una vez al mes.

🚀 Únete a miles de desarrolladores

DATE DE ALTA

x No me interesa | x Ya soy suscriptor

La mejor formación online para desarrolladores como tú

Comentarios (21) -

Muy  buen POST. Creo que es importante como programador aprender las dos formas de desarrollo. En mi caso trabajo mucho con EF en .NET pero siempre hay situaciones donde le metemos un SQL ya sea por rendimiento o claridad. Saludos desde Paraguay. Siempre los sigo.

Responder

Gracias José Manuel.
Actualmente estoy trabajando con EF Core y la verdad que doy fe de las desventajas que listas en el artículo. Definitivamente, hay que aprender a usar el ORM que estés usando en tu proyecto.

Por otro lado, ¿recomiendas alguna bibliografía/webgrafía en particular?  Me gustaría profundizar más en el tema.

Saludos!

Responder

José Manuel Alarcón
José Manuel Alarcón

Gracias por comebtar.

Pues la verdad es que los libros van de capa caída en todo el mundo y no tengo nada que recomendarte. Pero si nos das tiempo quizá tengamos el mejor recurso de aprendizaje sobre esto en algún momento del futuro ;-)

Saludos!

Responder

Tiago Barro
Tiago Barro

Gracias por el artículo José Manuel.

Por si a alguien le sirve nuestra experiencia:
- En 2007 empezamos el desarrollo de nuestro propio ORM. Todavía no existía ni EF ni Dapper. :-D

- El rendimiento de nuestra plataforma en Windows Forms tenía que ser muy alto por lo que decidimos desarrollar un ORM propio optimizado al máximo en función de nuestras necesidades y aprovechando la potencia de Sql Server. Teníamos claro que no nos sería necesario utilizar otras bbdd, con lo que se desarrolló pensando siempre en las oportunidades de rendimiento que ofrecía Sql Server.

- Utilizamos CodeSmithTools para la generación automática de código. Es decir, creamos la estructura de nuestras entidades en la base de datos y ejecutamos las plantillas de CodeSmith que atacan a estas tablas, con lo que se nos generan automáticamente los procedimientos almacenados necesarios (CRUD) sin tener que escribir ninguna línea de código y totalmente optimizados.

- También desarrollamos plantillas que nos generan las clases en C# de todas las entidades con lo que, sin escribir código, conseguimos: Las ventajas que has comentado al ser un ORM, alto rendimiento, control automático de concurrencia, auditoría automática, etc... Además ya se generan automáticamente las funciones más habituales de entidades: Carga de registro por indice principal, por filtros, ordenación, guardado automático con información del usuario, terminal, etc.., eventos de antes y después de guardar, antes y después de eliminar, etc...

- Actualmente estamos integrando Dapper con nuestro propio ORM aprovechando su ligereza y optimización.

En resumen: Con un desarrollo propio de ORM, obtienes un control mucho mayor y un rendimiento totalmente optimizado para tus necesidades.
Desventajas: Un curro impresionante hasta que no lo tienes totalmente desarrollado. :-D

Saludos!

Responder

José Manuel Alarcón
José Manuel Alarcón

Hola Tiago:

Muy interesante vuestra experiencia. Igual un día os interesa escribir un artículo para contar lo que habéis aprendido, bueno y malo, de crear algo así. Si es así, ya sabes: mándanoslo para publicarlo :-)

Saludos!

Responder

Tiago Barro
Tiago Barro

Hecho José Manuel.
Estaré encantado de escribir un artículo con nuestra experiencia.
Espero estar a la altura de vuestros posts! :-D

Un abrazo

Responder

Hola!

¿Y ese fantástico artículo se escribió en algún momento?

Saludos.

Responder

Tiago Barro
Tiago Barro

Gracias por el interés Joseba. Estamos en ello. :-D
Saludos!

Responder

¡Hola!

Tenemos noticias de ese fantástico artículo?

Responder

Jose Andrés
Jose Andrés

Fundador de campusMVP, es ingeniero industrial y especialista en consultoría de empresa[...]

Cuando un sujeto habla en tercera persona para referirse a sí mismo evidencia un sentimiento de despersonalización.

La despersonalización es una alteración de la percepción o la experiencia de uno mismo de tal manera que uno se siente "separado" de los procesos mentales o cuerpo, como si uno fuese un observador externo a los mismos.

Esto implica que no puede reconocerse en eso que dice o describe de sí mismo.

Es un trastorno psicosomático que viene desencadenado por la ansiedad, el estrés, o el consumo de algunas drogas. Algunos síntomas son mareos, dolores de cabeza y falta de concentración.

Si se refiere en términos de chiste o humor o en serio no cambia esta cuestión.

Si esto se hace en forma ocasional o como excepción no indicaría gran patología, pero si es la manera habitual de la persona de comunicarse es un claro signo de inestabilidad mental.

Es cierto que es un rasgo típico de la personalidad esquizoide porque hay una escisión del yo muy clara. El no poder decir YO... indica que algo se vive como ajeno o fuera de uno.

Responder

José Manuel Alarcón
José Manuel Alarcón

jajaja, me parto contigo :-)

Si vieses con detenimiento el blog verías que esa descripción está escrita de la misma manera para todos los autores, porque no se están describiendo a sí mismos, sino que el blog (sí, ese ente impersonal) está diciendo quién es el autor de cada post. Pero gracias por invertir tu tiempo en comentarlo.

Saludos!

Responder

No se lo tengas en cuenta,. El chaval estará haciendo algún cursillo de psicoanálisis y se ha emocionado imitando a Sigmund Freud. Ya ha aprendido que antes de hacer un psicoanálisis  es recomendable hacer un análisis del entorno del sujeto.

Responder

Llevo programando mas de 20 años sobre todo con access-vba y ahora estoy aprendiendo vs2019, c#, sql server y devexpress. Es un cambio muy grande  pero para mejorar. Estoy "pegándome" con las clases y ahora estoy con una clase para gestionar los albaranes. He creado 2, una para la cabecera y otra para las líneas pero en su artículo he visto la idea de tener una para las 2 cosas (propiedad factura.lineas), lo cual me parece muy bueno. ¿alguien tiene algún ejemplo, artículo, tutorial de como hacer esto? me gustaría aprenderlo para hacer las cosas lo mejor posible. Gracias.

Responder

Hola J. Carlos:

Si quieres aprender a fondo .NET y especialmente .NET Core que es el presente y el futuro de .NET te podemos recomendar nuestro curso:

www.campusmvp.es/.../....NET-Core-3-y-C-8_242.aspx

No vas a encontrar nada tan "potente" en el mercado, con soporte tutorial por el mismo experto que ha creado los contenidos, teoría, vídeos prácticos, multitud de ejemplos...

Incluye un módulo de Entity Framework, así como LINQ, acceso a datos tradicional, etc...

Saludos.

Responder

Hola,
Pretendo tener una única base de datos para mis posibles clientes de una aplicación web. Voy a guardar el ID_Cliente en todas las tablas del sistema para facilidad de acceso y porque creo que el rendimiento será mejor (evito multitud de joins) y me da más seguridad.
El tema es que me gustaría que cada vez que creo un registro grabar automáticamente el usuario y el ID_Cliente, que supongo las tendré como variables de entorno en todo momento, a partir del login (el front end es vía MVC en .Net Core). Eso, ¿se puede realizar en sql server de forma automática en vez de hacerlo como parte del código en las vistas o formularios?

Saludos,

Responder

José Manuel Alarcón
José Manuel Alarcón

Hola Álvaro:

En mi opinión es un error hacer eso que dices que vas a hacer. Los motores de base de datos relacionales empresariales como SQL Server están pensados para trabajar haciendo JOINs de tablas y si tienes bien los índices el coste de rendimiento de hacer uno o varios JOIN en una consulta es inapreciable/mínimo, y siempre será menos problemático a largo plazo que andar replicando el ID de los usuarios por todas partes. Además de que las claves externas sirven para muchas más cosas que para "simplemente" enlazarlas, y ayudan a mantener la integridad referencial, algo tan importante como el mero hecho de cruzar tablas.

En general, en un diseño de base de datos siempre deberías empezar con un diseño normalizado y solo si realmente te encuentras con problemas de rendimiento en un entorno real (lo que no midas es simple adivinación y no sirve), entonces empiezas a optimizar y hacer cosas "locas". De hecho, antes de hacer lo que dices seguramente puedes hacer otras optimizaciones en los índices, tipos de datos, etc... antes de tener que llega a eso.

Te recomiendo que le eches un vistazo a esto: https://go.campusmvp.es/crpnb3

En cuanto a lo que sugieres, si el dato del ID lo tienes en sesión en la parte cliente, siempre puedes meterlo a mano en todas las consultas, pero no puedes tenerlo "en sesión" (o similar) en la base de datos ya que ésta no puede ser consciente de que tu tabla de usuarios es eso, de usuarios. Otra cosa diferente es si estuvieses usando usuarios con nombre de SQL Server (o sea, del sistema operativo) que son los que acceden a tu aplicación y se autentican también contra SQL Server (ni me imagino el coste que tendrá esto para tu aplicación, en cuyo caso serán pocos y lo del rendimiento te da exactamente igual). En ese caso podrías obtener el usuario actual y guardarlo con un trigger.

Para todos estos escenarios avanzados de programación de SQL Server, también tenemos un curso muy potente, que entre otras cosas te enseña a hacer bien los diseños de las bases de datos:

https://go.campusmvp.es/e80uza

Espero haberte orientado.

Saludos.

Responder

Hola José Manuel,

Gracias por tu rápida respuesta. Haré el curso que comentas, es muy interesante y creo que "esencial", ahorraré tiempo haciendo las cosas bien dese el principio.

Pero el tema de ID_Cliente (me refiero a ID_Empresa -que tendrá "n "usuarios-, no a ID_Usuario)...ahí me has dejado algo preocupado. En muchas tablas es esencial ya que formará parte de la clave única; ej. los números de factura de 2 clientes (empresas) pueden ser exactamente los mismos y el número de factura como tal es una clave única, no puede duplicarse, pero sí entre dos ID_Cliente distintos. Esto es bastante común, casi cualquier Unique Key "habitual" lo será siempre por cada ID_Cliente (ej el DNI de una persona no se puede duplicar, pero puede que esa persona esté en 2 ID_Clientes (empresas) distintos e incluso con algún dato distinto (ej su mail o su dirección), eso ocurre. Por otro lado, que esté en todas las tablas (las necesarias y las no necesarias) quizás facilite la programación y la seguridad para no dar información de unas empresas a otras ¿?).

¿Campusmvp tiene algún servicio de "consultoría" -presencial u online-? Podría ser muy interesante para la gente que, como yo, estamos involucrados en nuevos proyectos y con una o dos horas de asesoría inicial podríamos resolver dudas importantes e iríamos por caminos más seguros.

Gracias de nuevo por tus consejos,
Álvaro

Responder

José Manuel Alarcón
José Manuel Alarcón

Hola de nuevo:

La verdad es que no conozco tu aplicación. Antes asumí que eran "clientes" en el sentido de gente que accede a tu aplicación y de hecho pensé que era una aplicación web y por lo que veo es más una de gestión. Por eso no me atrevo a darte más consejos, además de que yo no soy el experto de campusMVP en esto!!

Pero un par de cosas:

- Mucho ojo, aunque pueda parecer lo contrario, los DNIs no son únicos. De la época en la que no había ordenadores hay gente con DNIs duplicados (gente mayor, pero...) y por eso los bancos por ejemplo no los usan como clave única.
- Lo de las facturas con el mismo número pero en clientes diferentes no lo he visto antes. Generalmente lo que yo he visto son números de factura únicos por año y/o por línea de negocio, pero no numeraciones independientes por cliente. Pero cada aplicación tiene sus necesidades, claro, así que no sé.
- Lo de generar números únicos de factura ha sido tradicionalmente un tema complicado de hacer para verdaderamente asegurar que no te da problemas por simultaneidad de escritura. No te sé dar ahora mismo la mejor estrategia para ello, pero seguro que Internet tiene muchas opiniones al respecto ;-)

En cuanto a lo de la consultoría, lamentablemente no tenemos ese servicio. Nuestros tutores son todos gente muy ocupada que además de trabajar con nosotros tiene su trabajo del día a día (es uno de los valores: son gente que trabaja cada día con las tecnologías que enseña, no se dedican solo a enseñar), por lo que es inviable plantearles algo así. Pero gracias por la confianza :-)

Saludos y suerte con el proyecto.

Responder

Ok José Manuel, gracias a vosotros!

Álvaro

Responder

Excelente artículo.

Tengo una inquietud, llevo muchos años desarrollando stored procedures complejos y trabajando con. Net, en especial web forms derivado de que el 90% de las aplicaciones en mi trabajo están en ellos, así mismo hay otros compañeros que desarrollan mucho en sql.

Mi pregunta es, que alternativa habría a entitfy framework o core para hacer solo llamados a los stored procedures complejos ya desarrollados, ya que por lo que observó dicho nivel de complejidad no es tan facil llevar al lado de Code firts con ef para hacer consultas como con transact-sql

O no conviene migrar a dicho omr y seguir con la metodologia viejita que llevamos acá.


Muchas gracias

Responder

José Manuel Alarcón
José Manuel Alarcón

Hola Luis:

Desde EF puedes llamar a procedimientos almacenados y obtener los resultados en forma de objetos de tu aplicación, que la principal función de un ORM: "traducir" o "mapear" datos desde un almacén relacional a objetos de tus clases. Usar los procedimientos almacenados no es lo ideal ni lo más flexible, pero te funcionará.

Si no quieres utilizar EF porque prefieres lanzar consultas SQL y llamar a procedimientos almacenados, pero aún así obtener mapeado a objetos (que es muy útil), una buena opción sería utilizar el microORM llamado Dapper (https://github.com/StackExchange/Dapper). Dapper es una biblioteca de código abierto creada por StackOverflow que te permite hacer justo eso y además tener un rendimiento muy elevado. Es sencillo e aprender y de utilizar y seguramente encaja más con lo que estabas buscando. Funciona con .NET clásico, .NET Core y .NET

Saludos.

Responder

Agregar comentario

Los datos anteriores se utilizarán exclusivamente para permitirte hacer el comentario y, si lo seleccionas, notificarte de nuevos comentarios en este artículo, pero no se procesarán ni se utilizarán para ningún otro propósito. Lee nuestra política de privacidad.