Cómo manejar campos calculados complejos en un ORM

8

En nuestra API tenemos algunos tipos de datos centrales que deben ser "decorados" (por así decirlo) después de la recuperación de la base de datos con valores calculados. Se accede a la base de datos a través de un ORM que sigue una dinámica de tabla / entidad fuertemente inspirada en la capa de base de datos CakePHP 3, donde se usa un objeto de tabla como intermediario entre la base de datos y la aplicación que toma y distribuye filas como instancias de objeto modelo. Entonces, en lugar de solo recuperar datos de la base de datos y devolver esas filas, necesitamos preprocesar los datos devueltos antes de que realmente se puedan usar. Aquí hay algunos casos de uso que han surgido para explicar mejor lo que quiero decir:

  • Los objetos tienen valores numéricos que se traducen en etiquetas fáciles de usar (normalmente, esta es una lógica que mantendría únicamente en el cliente, pero por razones de seguridad empresarial, algunos de estos datos solo deben mantenerse en el servidor, es cierto caso extremo)
  • Los objetos deben tener un valor de calificación asociado que se extrae de la calificación agregada más recientemente
  • Basado en una combinación de valores calculados como este y valores almacenados, se construye un objeto de programación complejo

Por sí solos, cualquiera de estos individualmente es bastante fácil de hacer con una map()operación simple sobre el conjunto de resultados devuelto. Lo mismo se aplica cuando desea valores calculados múltiples, simplemente puede hacer más operaciones de mapa para calcular y agregar esos campos según sea necesario.

Dicho esto, este enfoque tiene dos inconvenientes principales:

  1. Significa que debe realizar un paso adicional de postprocesamiento en cualquier lugar donde desee trabajar con estos valores calculados, lo que no es particularmente SECO
  2. Algunas de estas transformaciones dependen de otras transformaciones que se realizan primero, de lo contrario simplemente no tienen los datos disponibles para trabajar

Para manejar ambos, he estado pensando que el mejor enfoque sería mover este código al ORM, luego modificar el ORM para que la interfaz (externamente) permita el acceso a los campos virtuales calculados de la misma manera que trata con las columnas de la base de datos . Internamente, podría asignar estos campos virtuales a funciones de transformación y determinar internamente cualquier posible transformación de dependencia necesaria para resolver el segundo problema.

(Como comentario aparte, me pregunto si esto también elimina la necesidad de que las filas devueltas sean objetos reales en lugar de simples hashes. En este momento, cada fila crea una instancia de un nuevo objeto con el conjunto de datos de campo, pero si todo el cálculo o la modificación de los datos se saca del modelo y el objeto simplemente se convierte en una bolsa de propiedades, un mapa de hash, esencialmente, sin lógica interna propia. Lo que en realidad puede no ser algo malo, creo)

moberemk
fuente
¿Cómo fue esto @moberemk?
Slamice
Si es demasiado difícil con ORM, puede usar una consulta SQL nativa. Por lo general, ORM proporciona la forma de realizar consultas SQL seguras porque saben bien que no pueden manejar todas las situaciones que se pueden hacer en SQL sin formato.
Walfrat

Respuestas:

3

Puede usar una capa similar a un repositorio para los casos mencionados anteriormente.

[Repositorio] Media entre el dominio y las capas de mapeo de datos utilizando una interfaz similar a una colección para acceder a los objetos del dominio.

Un repositorio por caso, que usa ORM para leer datos, los enriquece y devuelve.

Por lo tanto, tendría una forma unificada de acceder a tales instancias y ocultar cómo se crean esas instancias desde el exterior. Además, esto le permitirá cambiar de ORM a consultas SQL sin procesar sin cambiar la interfaz expuesta.

potfur
fuente
Esto es lo que terminé haciendo para este proyecto esencialmente, pero quiero señalar que hubo grandes problemas de rendimiento con esto en grandes conjuntos de datos. Esencialmente: funciona, pero no a escala. Sin embargo, aceptar la precisión.
moberemk
0

Estoy de acuerdo con @potfur. Dividir entre los "objetos de datos", que representan datos en la base de datos, y su representación "comercial", encapsular lógica adicional, cálculo, etc., es en mi humilde opinión la dirección correcta. La forma en que se representan los datos para un dominio / negocio determinado y qué se almacena técnicamente, puede ser algo completamente diferente. La implementación de la lógica empresarial con objetos que representan el dominio ayuda a agregar valor para el cliente y facilita la comunicación. En cuanto al ORM, usted menciona problemas de escalabilidad. Creo que un ORM es un antipatrón. Aunque es muy útil en escala pequeña / media, cuando se trata de escalabilidad, comienza a fallar. Lo que podría hacer es agregar una capa de almacenamiento en caché para las "entidades comerciales", de modo que no tenga que calcularlas cada vez.

David Lukac
fuente