Pregunta

El mapeo relacional de objetos se ha discutido bien, incluso aquí.Tengo experiencia con algunos enfoques y sus trampas y compromisos.La verdadera resolución parece requerir cambios en el OO o en los propios modelos relacionales.

Si se utiliza un lenguaje funcional, ¿se presenta el mismo problema?Me parece que estos dos paradigmas deberían encajar mejor que OO y RDBMS.La idea de pensar en conjuntos en un RDBMS parece encajar con el paralelismo automático que los enfoques funcionales parecen prometer.

¿Alguien tiene alguna opinión o idea interesante?¿Cuál es la situación en la industria?

¿Fue útil?

Solución

Los problemas difíciles de extender la base de datos relacional son transacciones extendidas, desajustes de tipo de datos, traducción automática de consultas y cosas como N + 1 Seleccione que son problemas fundamentales para abandonar el sistema relacional y, en mi opinión, no cambian cambiando el paradigma de programación de recepción.

Otros consejos

¿Cuál es el propósito de un ORM?

El objetivo principal de utilizar un ORM es tender un puente entre el modelo en red (orientación a objetos, gráficos, etc.) y el modelo relacional.Y la principal diferencia entre los dos modelos es sorprendentemente sencilla.Se trata de si los padres señalan a los hijos (modelo en red) o los hijos señalan a los padres (modelo relacional).

Con esta simplicidad en mente, creo no existe tal cosa como un "desajuste de impedancia" entre los dos modelos.Los problemas con los que suele toparse la gente son puramente específicos de la implementación y deberían poder solucionarse si existieran mejores protocolos de transferencia de datos entre clientes y servidores.

¿Cómo puede SQL abordar los problemas que tenemos con los ORM?

En particular, el tercer manifiesto intenta abordar las deficiencias del lenguaje SQL y el álgebra relacional permitiendo colecciones anidadas, que se han implementado en una variedad de bases de datos, que incluyen:

  • Oracle (probablemente la implementación más sofisticada)
  • PostgreSQL (hasta cierto punto)
  • informax
  • Servidor SQL, MySQL, etc.(mediante "emulación" vía XML o JSON)

En mi opinión, si todas las bases de datos implementaran el estándar SQL MULTISET() operador (por ej.Oracle lo hace), la gente ya no usaría ORM para mapeo (quizás todavía para la persistencia de gráficos de objetos), porque podrían materializar colecciones anidadas directamente desde las bases de datos, por ejemplo.esta consulta:

SELECT actor_id, first_name, last_name,
  MULTISET (
    SELECT film_id, title
    FROM film AS f
    JOIN film_actor AS fa USING (film_id)
    WHERE fa.actor_id = a.actor_id
  ) AS films
FROM actor AS a

Produciría a todos los actores y sus películas como una colección anidada, en lugar de un resultado de unión desnormalizado (donde los actores se repiten para cada película).

Paradigma funcional del lado del cliente

La cuestión de si un lenguaje de programación funcional en el lado del cliente es más adecuado para las interacciones con bases de datos es realmente ortogonal.Los ORM ayudan con la persistencia del gráfico de objetos, por lo que si su modelo del lado del cliente es un gráfico y desea que sea un gráfico, necesitará un ORM, independientemente de si está manipulando ese gráfico utilizando un lenguaje de programación funcional.

Sin embargo, debido a que la orientación a objetos es menos idiomática en los lenguajes de programación funcionales, es menos probable que introduzcas cada elemento de datos en un objeto.Para alguien que escribe SQL, proyectando arbitrariamente tuplas es muy natural.SQL adopta la tipificación estructural.Cada consulta SQL define su propio tipo de fila sin necesidad de asignarle previamente un nombre.Eso resuena muy bien con los programadores funcionales, especialmente cuando la inferencia de tipos es sofisticada, en cuyo caso nunca pensará en asignar su resultado SQL a algún objeto/clase previamente definido.

Un ejemplo en Java usando jOOQ de esta publicación de blog podría ser:

// Higher order, SQL query producing function:
public static ResultQuery<Record2<String, String>> actors(Function<Actor, Condition> p) {
    return ctx.select(ACTOR.FIRST_NAME, ACTOR.LAST_NAME)
              .from(ACTOR)
              .where(p.apply(ACTOR)));
}

Este enfoque conduce a una composicionalidad mucho mejor de las sentencias SQL que si el lenguaje SQL fuera abstraído por algún ORM, o si se utilizara la naturaleza natural "basada en cadenas" de SQL.La función anterior ahora se puede utilizar, p.como esto:

// Get only actors whose first name starts with "A"
for (Record rec : actors(a -> a.FIRST_NAME.like("A%")))
    System.out.println(rec);

Abstracción de FRM sobre SQL

Algunos FRM intentan abstraerse sobre el lenguaje SQL, generalmente por estos motivos:

  • Afirman que SQL no es lo suficientemente componible (jOOQ lo refuta, simplemente es muy difícil hacerlo bien).
  • Afirman que los usuarios de API están más acostumbrados a las API de recopilación "nativas", por lo que, por ejemplo. JOIN se traduce a flatMap() y WHERE se traduce a filter(), etc.

Para responder tu pregunta

FRM no es "más fácil" que ORM, resuelve un problema diferente.De hecho, FRM realmente no resuelve ningún problema en absoluto, porque SQL, al ser un lenguaje de programación declarativo en sí mismo (que no es tan diferente de la programación funcional), es una muy buena combinación para otros lenguajes de programación de clientes funcionales.Entonces, en todo caso, un FRM simplemente cierra la brecha entre SQL, el DSL externo y el lenguaje de su cliente.

(Trabajo para la empresa detrás jOOQ, por lo que esta respuesta está sesgada)

Eso depende de tus necesidades

  1. Si desea centrarse en las estructuras de datos, use un ORM como JPA / Hibernate
  2. Si desea arrojar luz sobre los tratamientos, eche un vistazo a las bibliotecas FRM: QueryDSL o Jooq
  3. Si necesita ajustar sus solicitudes SQL a bases de datos específicas, use JDBC y solicitudes SQL nativas

La fuerza de varios " Mapeo relacional " La tecnología es portabilidad: se asegura de que su aplicación se ejecute en la mayoría de las bases de datos ACID. De lo contrario, enfrentará las diferencias entre varios dialectos de SQL cuando escriba manualmente las solicitudes de SQL.

Por supuesto, puede restringirse al estándar SQL92 (y luego hacer una programación funcional) o puede reutilizar algunos conceptos de programación funcional con marcos ORM

Las fortalezas de ORM se crean sobre un objeto de sesión que puede actuar como un cuello de botella:

  1. gestiona el ciclo de vida de los objetos mientras se ejecuta la transacción de la base de datos subyacente.
  2. mantiene un mapeo uno a uno entre sus objetos java y las filas de su base de datos (y usa un caché interno para evitar objetos duplicados).
  3. detecta automáticamente las actualizaciones de asociación y los objetos huérfanos para eliminar
  4. maneja problemas concurrentes con bloqueo optimista o pesimista.

Sin embargo, sus fortalezas son también sus debilidades:

  1. La sesión debe poder comparar objetos, por lo que debe implementar métodos equals / hashCode. Pero la igualdad de objetos debe basarse en & Quot; Business Keys & Quot; y no el ID de la base de datos (¡los nuevos objetos transitorios no tienen ID de base de datos!). Sin embargo, algunos conceptos reificados no tienen igualdad comercial (una operación, por ejemplo). Una solución alternativa común se basa en los GUID que tienden a molestar a los administradores de bases de datos.

  2. La sesión debe espiar los cambios de relación, pero sus reglas de mapeo hacen que el uso de colecciones no sea adecuado para los algoritmos comerciales. En algún momento le gustaría usar un HashMap pero el ORM requerirá que la clave sea otro & "; Rich Domain Object &"; en lugar de otro ligero ... Luego debe implementar la igualdad de objetos en el objeto de dominio rico que actúa como una clave ... Pero no puede porque este objeto no tiene contraparte en el mundo de los negocios. Por lo tanto, recurre a una lista simple en la que debe iterar (y los problemas de rendimiento resultan).

  3. Las API de ORM a veces no son adecuadas para el uso en el mundo real. Por ejemplo, las aplicaciones web del mundo real intentan forzar el aislamiento de la sesión agregando algunas & Quot; WHERE & Quot; cláusulas cuando obtiene datos ... Entonces el & Quot; Session.get (id) & Quot; no es suficiente y necesita recurrir a DSL más complejo (HSQL, Criteria API) o volver a SQL nativo

  4. Los objetos de la base de datos entran en conflicto con otros objetos dedicados a otros marcos (como OXM frameworks = Object / XML Mapping). Por ejemplo, si sus servicios REST usan la biblioteca jackson para serializar un objeto comercial. Pero este Jackson se asigna exactamente a Hibernate One. Luego, combina ambos y aparece un fuerte acoplamiento entre su API y su base de datos O debe implementar una traducción y todo el código que guardó del ORM se pierde allí ...

Por otro lado, FRM es una compensación entre & "; Mapeo Relacional de Objetos &"; (ORM) y consultas SQL nativas (con JDBC)

La mejor manera de explicar las diferencias entre FRM y ORM consiste en adoptar un enfoque DDD.

  • El mapeo relacional de objetos permite el uso de " Rich Domain Object " que son clases Java cuyos estados son mutables durante la transacción de la base de datos
  • El mapeo relacional funcional se basa en " Objetos de dominio pobres " que son inmutables (tanto que debe clonar uno nuevo cada vez que quiera alterar su contenido)

Libera las restricciones impuestas a la sesión ORM y se basa la mayor parte del tiempo en un DSLel SQL (por lo que la portabilidad no importa) Pero, por otro lado, debe analizar los detalles de la transacción, los problemas de concurrencia

List<Person> persons = queryFactory.selectFrom(person)
  .where(
    person.firstName.eq("John"),
    person.lastName.eq("Doe"))
  .fetch();

Supongo que el mapeo funcional a relacional debería ser más fácil de crear y usar que OO a RDBMS. Siempre que solo consulte la base de datos, es decir. Realmente no veo (todavía) cómo podría hacer actualizaciones de la base de datos sin efectos secundarios de una manera agradable.

El principal problema que veo es el rendimiento. Los RDMS actuales no están diseñados para ser utilizados con consultas funcionales, y probablemente se comportarán mal en algunos casos.

No he realizado el mapeo funcional-relacional, per se , pero he usado técnicas de programación funcional para acelerar el acceso a un RDBMS.

Es bastante común comenzar con un conjunto de datos, realizar algunos cálculos complejos y almacenar los resultados, donde los resultados son un subconjunto del original con valores adicionales, por ejemplo. El enfoque imperativo dicta que almacene su conjunto de datos inicial con columnas NULL adicionales, haga su cálculo y luego actualice los registros con los valores calculados.

Parece razonable. Pero el problema con eso es que puede ser muy lento. Si su cálculo requiere otra instrucción SQL además de la consulta de actualización en sí, o incluso necesita hacerse en el código de la aplicación, literalmente debe (re) buscar los registros que está cambiando después del cálculo para almacenar sus resultados en las filas correctas .

Puede solucionar esto simplemente creando una nueva tabla de resultados. De esta manera, siempre puede insertar en lugar de actualizar. Termina teniendo otra tabla, duplicando las claves, pero ya no necesita desperdiciar espacio en columnas que almacenan NULL & # 8211; solo guardas lo que tienes. Luego, une sus resultados en su selección final.

I (ab) usé un RDBMS de esta manera y terminé escribiendo sentencias SQL que se veían principalmente así ...

create table temp_foo_1 as select ...;
create table temp_foo_2 as select ...;
...
create table foo_results as
  select * from temp_foo_n inner join temp_foo_1 ... inner join temp_foo_2 ...;

Lo que esto está haciendo esencialmente es crear un montón de enlaces inmutables. Sin embargo, lo bueno es que puedes trabajar en sets completos a la vez. Te recuerda los idiomas que te permiten trabajar con matrices, como Matlab.

Me imagino que esto también permitiría el paralelismo mucho más fácil.

Una ventaja adicional es que los tipos de columnas para tablas creadas de esta manera no tienen que especificarse porque se infieren de las columnas de las que se seleccionan.

Creo que, como mencionó Sam, si la base de datos se debe actualizar, se deben enfrentar los mismos problemas de concurrencia que con OO world. La naturaleza funcional del programa podría ser incluso un poco más problemática que la naturaleza del objeto debido al estado de los datos, las transacciones, etc. del RDBMS.

Pero para leer, el lenguaje funcional podría ser más natural con algunos dominios problemáticos (como parece ser independientemente del DB)

El mapeo funcional < - > RDBMS no debería tener grandes diferencias con los mapeos OO < - > RDMBS. Pero creo que eso depende mucho de qué tipo de datos desea usar, si desea desarrollar un programa con un nuevo esquema de base de datos o hacer algo en contra de un esquema de base de datos heredado, etc.

Las recuperaciones diferidas, etc. para asociaciones, por ejemplo, probablemente podrían implementarse bastante bien con algunos conceptos relacionados con la evaluación diferida. (Aunque también se pueden hacer bastante bien con OO)

Editar: con algunas búsquedas en Google encontré HaskellDB (biblioteca SQL para Haskell): ¿podría valer la pena intentarlo?

Las bases de datos y la programación funcional se pueden fusionar.

por ejemplo:

Clojure es un lenguaje de programación funcional basado en la teoría de bases de datos relacionales.

               Clojure -> DBMS, Super Foxpro
                   STM -> Transaction,MVCC
Persistent Collections -> db, table, col
              hash-map -> indexed data
                 Watch -> trigger, log
                  Spec -> constraint
              Core API -> SQL, Built-in function
              function -> Stored Procedure
             Meta Data -> System Table

Nota: En la última especificación2, la especificación se parece más a RMDB. ver: wiki spec-alpha2: Schema-and-select

Abogo por: Construir un modelo de datos relacionales sobre el mapa hash para lograr una combinación de ventajas NoSQL y RMDB. Esta es en realidad una implementación inversa de posgtresql.

Tipo de pato: si parece un pato y grazna como un pato, debe ser un pato.

Si el modelo de datos de clojure como un RMDB, las instalaciones de clojure como un RMDB y la manipulación de datos de clojure como un RMDB, clojure debe ser un RMDB.

Clojure es un lenguaje de programación funcional basado en la teoría de bases de datos relacionales

Todo es RMDB

Implemente el modelo de datos relacionales y la programación basada en hash-map (NoSQL )

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top