database - significado - mnesia elixir
Preservar la integridad relacional con Mnesia (2)
Prefiero usar GUIDs en lugar de ints autoincrementables como claves foráneas artificiales. Hay un módulo uuid de Erlang disponible en GitHub, o puede usar {now(), node()}
, dado que now/0
doc dice: "También se garantiza que las llamadas subsiguientes a este BIF devuelvan valores continuamente en aumento".
Usar algo que puede cambiar como la clave principal me parece una mala idea, independientemente del sistema de base de datos.
No olvide que no necesita normalizar los datos en Mnesia ni siquiera a la primera forma normal; en su ejemplo, consideraría la siguiente estructura:
-record(user, {id, name, salt, pass_hash, email, entries}).
-record(entry, {id, title, body, slug, users}).
donde las entries
y los users
son listas de identificadores. Por supuesto, esto depende de las consultas que desee.
EDITAR: fijado para ser de muchos a muchos en lugar de muchos a uno.
He estado buceando en Erlang recientemente, y decidí usar Mnesia para hacer mi trabajo de base de datos dado que puede almacenar cualquier tipo de estructura de datos de Erlang sin problemas, escalar con facilidad, ser utilizado con listas de comprensión, etc.
Procedentes de bases de datos SQL estándar, la mayoría de las filas pueden y deben identificarse con una clave principal, generalmente un entero de incremento automático. Por defecto, Mnesia considera que el primer campo de una fila es su clave. Tampoco da ninguna forma de tener una clave entera autoincrementada hasta donde yo sé.
Dado que tengo estos registros ficticios que representan mis tablas:
-record(user, {name, salt, pass_hash, email}).
-record(entry, {title, body, slug}).
-record(user_entry, {user_name, entry_title}).
Me imagino que usar el nombre de usuario puede ser lo suficientemente bueno para algunos propósitos, como con el título de la entrada, para identificar el recurso, pero ¿cómo hago para mantener la integridad?
Digamos que el usuario cambia su nombre o que el título de la entrada cambia después de una edición. ¿Cómo me aseguro de que mis datos estén correctamente relacionados? Actualizar cada tabla con el nombre de usuario cuando cambia suena como una idea terrible sin importar cómo se publique.
¿Cuál sería la mejor manera de implementar algún tipo de sistema de llave primaria en Mnesia?
Además, ¿cómo funcionaría una tabla intermedia como ''user_entry'' si el primer campo es generalmente la clave? De lo contrario, ¿cuál sería una mejor forma de representar una relación de muchos a muchos en Mnesia?
Mnesia admite secuencias (enteros mnesia:dirty_update_counter(Table, Key, Increment)
) en forma de mnesia:dirty_update_counter(Table, Key, Increment)
. Para usarlo necesitas una tabla con dos atributos Key y Count. A pesar del nombre, dirty_update_counter es atómico aunque no se ejecute dentro de una transacción.
Ulf Wiger trabajó en la provisión de características típicas de RDBMS además de mnesia en su paquete rdbms . Su código proporciona restricciones de clave externa, índices paramétricos, restricciones de valor de campo, etc. Lamentablemente, este código no se ha actualizado en dos años y probablemente será difícil de ejecutar sin una buena experiencia de Erlang.
Al diseñar y usar mnesia, debe recordar que mnesia no es una base de datos relacional. Es un almacén de clave / valor transaccional y es mucho más fácil de usar cuando no se normaliza.
Si sus nombres de usuario son únicos, puede usar el esquema:
-record(user, {name, salt, pass_hash, email}).
-record(entry, {posted, title, body, slug, user_name}).
Donde se posted
es la hora de erlang: now () cuando se carga el artículo. user_name
puede necesitar un índice secundario si a menudo necesita recuperar una lista de todos los artículos para un usuario. Como estos datos se dividen en dos tablas, deberá imponer cualquier restricción de integridad en el código de su aplicación (por ejemplo, no aceptar entradas sin un nombre de usuario válido).
Cada valor de campo en mnesia puede ser cualquier término erlang, por lo que si no puede obtener una clave única en un campo en particular, a menudo puede combinar algunos campos para darle un valor que siempre será único, quizás {nombre de usuario, DatePosted, TimePosted}. Mnesia le permite buscar claves parciales a través de mnesia:select(Table, MatchSpec)
. Las MatchSpecs son bastante difíciles de escribir a mano, así que recuerda que ets:fun2ms/1
puede convertir una función de psuedo erlang en una especificación de coincidencia por ti.
En este ejemplo, fun2ms nos genera una especificación de coincidencia para buscar en una entrada de blog table -record(entry, {key, title, slug, body}).
donde la clave es {Username, {Year, Month, Day}, {Hour, Minute, Second}}
- el nombre de usuario del autor y la fecha y hora en que se publicó el artículo. El siguiente ejemplo recupera los títulos de todas las publicaciones de blog por TargetUsername
durante diciembre de 2008.
ets:fun2ms(fun (#entry{key={U, {Y,M,_D}, _Time}, title=T})
when U=:=TargetUsername, Y=:=2008, M=:=12 ->
T
end).