2011-04-27 6 views
7

En los lenguajes de OOP podría escribir un contenedor de base de datos que encapsula la conexión de base de datos, administra el esquema y proporciona algunas operaciones centrales, como exec, query, prepare_and_execute. Incluso podría tener una clase auxiliar de base de datos separada que manejaría el esquema de la base de datos, dejando la abstracción de la base de datos solo para manejar las conexiones. Esto luego sería utilizado por envoltorios/fábricas de modelos que usan la clase de abstracción de la base de datos para crear instancias de clases modelo. Algo a lo largo de la línea como este diagrama UML: Idiomatic haskell para abstracción de base de datos

¿Cuál sería la forma preferida de diseñar un sistema de este tipo en haskell idiomático?

+1

Tal vez http://blog.ezyang.com/2010/06/databases-are-categories/ vale la pena mirar. –

+0

@Alexandre gracias, una buena lectura, pero no creo que sea lo que estaba buscando :) – Masse

+2

Su diagrama ya no existe. ¿Puedes subirlo de nuevo? Esta pregunta más bien depende de eso. –

Respuesta

4

La biblioteca de abstracción de base de datos más utilizada en Haskell es HDBC. Significa que las consultas simplemente se representan como String s con marcadores de posición. Menos personas usan HaskellDB, lo que proporciona una forma segura de generar consultas. Nada prohíbe tener tipos de datos de usuario para representar consultas comunes y funciones personalizadas para construirlos.

Los valores en Haskell son inmutables, lo que significa que no es útil tener un objeto mutable correspondiente a un registro en la base de datos. En cambio, creo que es más común definir tipos de datos de usuario y funciones que marcan y empujan/extraen valores de estos tipos hacia/desde la base de datos.

Cuando sea necesario actualizar la base de datos, es probable que se ejecute en una mónada con estado bajo IO. Esto permitiría mantener la conexión abierta, por ejemplo, o hacer algo entre las solicitudes.

Finalmente, las funciones son de primera clase, por lo que es posible construir todas las funciones sobre la marcha. Entonces, una función en sí misma puede encapsular cualquier información que desee.

lo tanto, creo, el enfoque habitual Haskell consiste en

  • tipos de datos algebraicos para representar los datos reales (como inmutables valores)
  • el resto de la aplicación para transformar estos valores
  • funciones que generan consultas (encapsulan detalles de esquema, marcan datos a/de tipos de datos Haskell)
  • (opcionalmente) una mónada con estado para ejecutar consultas (ocultar detalles del acceso a la base de datos)
  • funciones que se ejecutan las consultas (ocultar detalles de acceso de base de datos)
+0

Tenía algo similar en mente. ¿Podrías profundizar en la parte "una mónada con estado para ejecutar consultas"? Hace un tiempo escribí una prueba de concepto de abstracción sobre HDBC donde usé Reader mónada para ocultar detalles de conexión (runDatabase haría la conexión, ejecutaría el lector con el valor de conexión y luego cerraría la conexión). También tenía ADT que representaba la Persona y la Ubicación y algo así como "getLocation :: Int -> IO Location" y "getPerson :: Int -> IO Person". Para modificar db, tenía algo así como "savePerson :: Person -> IO()". ¿Es esto lo que tienes en mente? – Masse

+0

@Masse Quise decir que, si, por ejemplo, desea compilar algunas o todas las declaraciones, ejecute ['prepare'] (http://hackage.haskell.org/packages/archive/HDBC/latest/doc/html /Database-HDBC.html#v:prepare) en ellos y necesita un lugar para mantener las declaraciones compiladas entre consultas. Entonces puede usar 'tipo DB a = StateT [(Query, Statement)] IO a' para guardarlos (supongo que una declaración está representada por un tipo de datos' Query' personalizado que implementa 'Eq'). En el nivel superior tendría algo como 'runDB :: FilePath -> DB a -> IO a',' conPersona :: Query -> Key -> (Person -> (a, Maybe Person)) -> DB a '... – sastanin

0

La forma más idiomática de la utilización de Haskell para bases de datos, y el más eficiente, en mi humilde opinión, es para almacenar en caché los registros en la memoria y el uso de STM en la memoria transacciones, para que use la base de datos para el almacenamiento. Luego, puede usar variables transaccionales (TVar's) para su gestión de registros. Pero debe definir su propio lenguaje de consulta y necesita un mecanismo para el almacenamiento en caché, el almacenamiento en memoria caché y la sincronización. Eso es, después de todo, lo que hace java EJB3 y Hybernate.

El paquete TCache define DBRefs, que son persistentes STM variables with TVar semantics. Pueden ser parte de un registro y señalar a otro registro y son livianos, por lo que puede desarrollar su propia abstracción sobre él. También tiene un lenguaje de consulta similar a SQL, que incluye field search, joins y búsqueda de texto completo. Tiene persistencia predeterminada en los archivos. Solo necesita definir una clave para su registro Haskell y tiene persistencia de archivos. Para la persistencia de la base de datos hay una clase IResource donde se definen las operaciones de lectura, escritura y eliminación para sus registros.Cada registro puede tener su propia persistencia. Entonces, toda la interacción de la base de datos está en una sola ubicación del código fuente, y las transacciones en la memoria son órdenes de magnitud más rápidas. TCache escribe un estado coherente cada vez que escribe de forma asíncrona en la base de datos. Puede escribir sincrónicamente también.

+0

No puede evitar la sensación de que hay un caso grave de síndrome NIF en el trabajo aquí. – Masse

+0

¿Qué se supone que significa el síndrome NIF? Si no entiende lo que quiero decir, solicite una aclaración. Si no está interesado, un simple agradecimiento o no decir nada es suficiente. Si no se siente cómodo con mi respuesta, tome una taza de té. – agocorona

+0

* NIH. "Aquí". Error de tipografía. Lo siento – Masse

Cuestiones relacionadas