2008-12-27 72 views
10

我最近一直在潜入Erlang,并决定使用Mnesia来完成我的数据库工作,因为它可以存储任何类型的Erlang数据结构,而且没有问题,可以轻松扩展,可以与列表一起使用理解等保留与Mnesia的关系完整性

来自标准SQL数据库,大多数行可以并应该由主键标识,通常是自动递增整数。默认情况下,Mnesia认为一行的第一个字段是它的关键。据我所知,它也无法拥有自动递增的整数键。

鉴于我有这些虚构的记录代表我的表:

-record(user, {name, salt, pass_hash, email}). 
-record(entry, {title, body, slug}). 
-record(user_entry, {user_name, entry_title}). 

我想使用的用户名可能是足够好为了某些目的,如条目标题,以识别资源,但是怎么办我去保持诚信?

假设用户更改了其名称,或者编辑后条目的标题发生了变化。我如何确保我的数据仍然正确相关?更改每个表时使用用户名,当它改变听起来像一个可怕的想法,不管它如何放置。

在Mnesia中实现某种主键系统的最佳方式是什么?

此外,如果第一个字段通常是关键字,那么中间表如'user_entry'会如何执行?否则,在Mnesia中代表多对多关系的更好方法是什么?

回答

9

我更喜欢使用GUID而不是自动递增整数作为人造外键。有一个Erlang uuid module可用在 GitHub,或者您可以使用{now(), node()},因为now/0文档说:“它也保证后续调用此BIF返回不断增加值。”

使用可以改变为主键的东西似乎是独立于数据库系统的坏主意。

不要忘记,你不需要规范Mnesia的数据,甚至是第一范式;在你的榜样,我会考虑以下结构:

-record(user, {id, name, salt, pass_hash, email, entries}). 
-record(entry, {id, title, body, slug, users}). 

其中entriesusers是ID列表。当然,这取决于你想要的查询。

编辑:固定为多对多而不是多对一。

+0

它真的是好方法吗?看起来make_ref/0在重新启动shell后会重置它的计数,并且会有多个相似的值。那不就是说你可以在服务器重启后得到错误的密钥吗?也许,将它与now/0耦合可能会有所帮助。 – 2008-12-27 21:43:44

+1

实际上将now/0与node/0结合起来可能会更好。 – 2008-12-28 08:14:55

8

Mnesia不支持mnesia:dirty_update_counter(Table, Key, Increment)形式的序列(自动递增整数)。要使用它,你需要一个带有两个属性Key和Count的表。尽管有这个名字,dirty_update_counter是原子的,即使它不在事务中运行。

Ulf Wiger在他的rdbms package上做了一些工作,在mnesia的顶部提供典型的RDBMS功能。他的代码提供了外键约束,参数化索引,字段值约束等。不幸的是,这段代码在两年内还没有更新,如果没有Erlang的经验,可能很难运行。

在设计和使用mnesia时,应该记住mnesia不是一个关系数据库。这是一个交易密钥/值存储,当你不规范化时更容易使用。

如果你的用户名是唯一的,你可以使用模式:

-record(user, {name, salt, pass_hash, email}). 
-record(entry, {posted, title, body, slug, user_name}). 

哪里posted是二郎:现在()时的文章上载。如果您经常需要为用户检索所有文章的列表,则user_name可能需要辅助索引。由于此数据分为两个表,因此您必须在应用程序代码中强制执行任何完整性约束(例如,不接受没有有效user_name的条目)。

mnesia中的每个字段值都可以是任何erlang字词,所以如果您在任何一个特定字段上都遇到唯一键的缺失,通常可以组合一些字段来为您提供永远是唯一的值 - 也许{Username,DatePosted,TimePosted}。 Mnesia允许您通过mnesia:select(Table, MatchSpec)搜索部分密钥。 MatchSpecs非常难以手工编写,所以请记住ets:fun2ms/1可以将psuedo erlang函数转换为您的matchspec。

在本例中,fun2ms为我们生成一个matchspec,用于搜索博客条目表​​,其中关键是{Username, {Year, Month, Day}, {Hour, Minute, Second}} - 作者的用户名以及文章的发布日期和时间。以下示例在2008年12月期间按TargetUsername检索了所有博客文章的标题。

ets:fun2ms(fun (#entry{key={U, {Y,M,_D}, _Time}, title=T}) 
      when U=:=TargetUsername, Y=:=2008, M=:=12 -> 
       T 
      end).