这篇内容的主要思想来自JackRabbit的WIKI,http://wiki.apache.org/jackrabbit/DavidsModel,作者在这篇文章中阐述了其JCR内容建模的观点。
软件行业对关系型数据的建模已经拥有许多经验,但是在内容仓库方面,我们还停留在早期阶段。
规则一:数据第一,结构其次。
我建议在软件开发的早期阶段不去理会数据类型。
尝试在开发阶段使用nt:unstructured。
设计数据结构代价高昂,而且在许多情况下,对于底层存储来说,精确描述数据结构是完全没有必要的。
应用程序中使用的数据结构自有其规律。比方说我将BLOG的修改日期保存在“lastModified”属性中,我的应用程序会自动知道从同一属性中读回修改日期,没必要进行精确描述。
更多的数据约束(如数据类型)仅在数据集成时需要。
例子:
前 面的例子中“lastModified”这个日期属性,没必要为其指定节点类型。我一定会在一开始使用“nt:unstructured”。因为我的 BLOG应用程序只是想显示最后一次修改的日期(或许还要排序),我几乎不关心它是不是一个日期。我完全相信我的程序会写入一个“日期”,也就没有必要声 明“lastModified”的节点类型。
规则二:控制数据层次,不要随意处之
内容的层次是一个非常有价值的资产,不要随意处之,要设计。如果你没有“好的”,可读的节点名称,可能你必须重新考虑,随意的数字比不上好名称。
将关系型数据模型转入层次型模型时,应对其过程进行斟酌。
按我的经验,内容层次要考虑访问控制,就像你的文件系统。
我更喜欢在初期讨论内容层次,在后面的阶段谈论数据类型。
例子:
我会按下面的说明为一个简单的BLOG系统建模,请注意我并未考虑节点类型。
/content/myblog
/content/myblog/posts
/content/myblog/posts/what_i_learned_today
/content/myblog/posts/iphone_shipping
/content/myblog/comments/iphone_shipping/i_like_it_too
/content/myblog/comments/iphone_shipping/i_like_it_too/i_hate_it
即使不进行说明,我们所有人也都理解这个例子的内容结构。
会有一点意外,为什么我没有将“comments”与“posts”保存到一起?是因为需要施加一个合理的分级访问控制。
使用上述模型,我可以轻易地允许“anonymous”用户编辑评论,而对工作区中的其它内容仅保持只读权限。
规则三:工作区(workspace)是用来克隆、合并和修改的
如果你的应用程序不使用clone(),merge()或update()方法,就使用单一工作区。
"Corresponding nodes"是JCR规范中的一个概念,本质上,它可以归结为不同workspace中拥有相同内容的节点。
JCR中workspace的概念非常抽象,很多开发者不理解如何运用。我建议按照下面的说明来使用它。
如果你要考虑多workspace中"Corresponding nodes"(典型的情况是拥有相同的UUID)的异同,使用多workspace是正确的。换言之,如果不同workspace中相同UUID节点的内容完全不同,那就是错误的用法。
workspace不应用来进行访问控制。不应为了区分哪些用户该看到哪些内容,而把内容划分到不同的workspace中去,JCR中的“Access Control”章节说明了正确的做法。
例子:
这样使用workspace:
- 为项目区分1.2和1.3版本。
- 内容的“development”、“qa”和“已发布”状态。
不要这样使用workspace:
- 用户的home目录。
- 区分“public”、“private”、“local”内容。
- 不同用户的收件箱。
规则四:小心同名的兄弟节点
JCR中的同名兄弟节点(SNS),是为了兼容XML,SNS会引发很大的麻烦。
如果库中包含SNS,任何路径都会变得不安全,如果删除或记录SNS,它会影响该路径下的其它SNS及其子节点。
为了导入XML,或与现存的XML兼容,SNS可能是必要的,但是我绝不会使用SNS。
例子
使用
/content/myblog/posts/what_i_learned_today /content/myblog/posts/iphone_shipping
而不是
/content/blog[1]/post[1] /content/blog[1]/post[2]
规则五:引用的害处
引用实现涉及完整性。引用不但增加了库管理难度,也给内容的扩展性带来了难度。
我使用路径、名称和UUID来指向其它节点,只在万不得已的时候使用引用。
规则六:文件就是文件
如果一个内容模型类似文件或文件夹,我会用(或扩展)nt:file,nt:folder和nt:resource。
以我的经验,许多程序天生能够集成“nt:file”,“nt:folder”,即使它们包含附加元信息,也知道如何让处理和显示它们。例如,基于JCR的Webdav或CIFS应用能够直接使用这些内容。
如果你需要存储文件名和MIME类型,那么nt:file/nt:resource恰好满足要求,如果有多个文件,在nt:folder节点会是一个好地方。
例子:
设想上传图片到BLOG条目
/content/myblog/posts/iphone_shipping
文件名和MIME类型都没什么用,考虑为其添加一个包含图片的二进制属性,也没有问题。
我建议按照下面的结构存储内容
/content/myblog/posts/iphone_shipping/attachments [nt:folder] /content/myblog/posts/iphone_shipping/attachments/front.jpg [nt:file] /content/myblog/posts/iphone_shipping/attachments/front.jpg/jcr:content [nt:resource]
规则七:ID有害
在关系型数据库中,必要的ID用来表达关系,人们在内容模型中也倾向于使用ID。
如果你的内容模型中满是以"id”结尾的属性,你恐怕没有将内容层次设计好。
的确,一些节点在其生命周期中需要安全的标识。你可能没有想到,库内建了mix:referenceable机制,实在没有必要再添加标识节点的方法。
还要记住,路径可以标识节点。
更重要的是,**mix**:referenceable意思是在你实际需要引用一个节点的时候,可以被运用到该节点上。
例子:
使用
/content/myblog/posts/iphone_shipping/attachments/front.jpg
而不是
[Blog] - blogId - author [Post] - postId - blogId - title - text - date [Attachment] - attachmentId - postId - filename + resource (nt:resource)