2009-12-19 74 views
2

我想弄清楚如何爲帖子和其他內容設置修訂系統。我認爲這意味着它需要使用基本的belongs_to/has_one/has_many/has_many_though ORM(任何好的ORM都應該支持這一點)。如何使用ORM設置發佈修訂/歷史跟蹤?

我在想一個我能有一個像一些表(含配套機型)

[[POST]] (has_many (text) through (revisions) 
id 
title 

[[Revisions]] (belongs_to posts/text) 
id 
post_id 
text_id 
date 

[[TEXT]] 
id 
body 
user_id 

在那裏我可以加入通過修改表以獲取最新的文本正文。但是我對它的工作方式有點模糊。有沒有人設置這樣的東西?

基本上,我需要能夠加載文章並請求最新的內容條目。

// Get the post row 
$post = new Model_Post($id); 
// Get the latest revision (JOIN through revisions to TEXT) and print that body. 
$post->text->body; 

有能力隨時調整回到以前的修訂和刪除修訂也將是一個很大的幫助。

無論如何,這些只是我認爲某種歷史追蹤會起作用的想法。我願意接受任何形式的跟蹤,我只想知道最佳做法是什麼。

:編輯:

看來,向前走,兩個表似乎最有意義。由於我打算存儲文本的兩個副本,這也將有助於節省空間。第一個表格posts將存儲當前修訂版本的數據以進行快速讀取而無需任何連接。帖子body將是匹配版本的text字段的值 - 但通過markdown/bbcode/tidy/etc進行處理。這將允許我保留原始文本(用於下一次編輯),而不必在一個修訂行中存儲該文本兩次(或者每次顯示時都必須重新解析它)。

所以抓取將是ORM友好的。然後,爲了創建/更新,我將不得不分別處理修訂版,然後使用新的當前修訂版值更新後期對象。

CREATE TABLE IF NOT EXISTS `posts` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `published` tinyint(1) unsigned DEFAULT NULL, 
    `allow_comments` tinyint(1) unsigned DEFAULT NULL, 
    `user_id` int(11) NOT NULL, 
    `title` varchar(100) NOT NULL, 
    `body` text NOT NULL, 
    `created` datetime NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `user_id` (`user_id`), 
    KEY `published` (`published`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ; 

CREATE TABLE IF NOT EXISTS `postsrevisions` (
    `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 
    `post_id` int(10) unsigned NOT NULL, 
    `user_id` int(10) unsigned NOT NULL, 
    `is_current` tinyint(1) unsigned DEFAULT NULL, 
    `date` datetime NOT NULL, 
    `title` varchar(100) NOT NULL, 
    `text` text NOT NULL, 
    `image` varchar(200) NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `post_id` (`post_id`), 
    KEY `user_id` (`user_id`), 
    KEY `is_current` (`is_current`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ; 
+0

這並不容易弄清楚你想知道:) – 2009-12-22 13:22:04

回答

2

您的Revisions表,如您所示,它建模了PostsText之間的多對多關係。這可能是而不是你想要什麼,除非Text中的給定行可以提供Posts中多行的內容。這不是大多數CMS架構的工作原理。

你肯定不需要三張表。我不知道爲什麼你認爲這是3NF所需要的。 3NF的意義在於屬性不應該依賴於非關鍵屬性,它並不是說你應該不必要地分裂成多個表。

因此,您可能只需要兩個表格之間的一對多關係:PostsRevisions。也就是說,對於每篇文章,可以有多個修訂,但是給定的修訂只適用於一篇文章。也有人建議尋找當前後兩個選擇:

  • Revisions標誌列,要注意當前版本。更改當前版本與在所需版本中將標誌更改爲true一樣簡單,而對於以前的當前版本,則更改爲false。

  • Posts中的外鍵指向給定帖子當前的修訂版本。這更簡單,因爲您可以在一次更新而不是兩次更改當前修訂版本。但是圓形外鍵引用可能會導致問題面對面的人備份&恢復,級聯更新等

你甚至可以實現使用單個表修正系統:

CREATE TABLE PostRevisions (
    post_revision_id SERIAL PRIMARY KEY, 
    post_id INT NOT NULL, 
    is_current TINYINT NULL, 
    date DATE, 
    title VARCHAR(80) NOT NULL, 
    text TEXT NOT NULL, 
    UNIQUE KEY (post_id, is_current) 
); 

我不確定這是重複存儲每個修訂版title,因爲標題可以像文本一樣進行修改,不是嗎?

is_current應該是1或NULL。一個唯一的約束不會計數NULL,因此您可以只有一行,其中is_current爲1,而無限數量的行爲NULL。

這確實需要更新兩行才能使修訂爲最新版本,但是通過將模型簡化爲單個表格可以獲得一些簡單性。當你使用ORM時,這是一個很大的優勢。

您可以創建一個視圖簡化查詢當前職位的常見情況:

CREATE VIEW Posts AS SELECT * FROM PostRevisions WHERE is_current = 1; 

更新:重新更新的問題:我同意適當的關係設計會鼓勵兩個表,這樣您可以對Post的某些屬性進行修改,使其不變。但是大多數ORM工具假定一個實體存在於一個表中,而ORM在連接多個表中的行以構成一個給定的實體時很笨拙。所以我會說,如果使用ORM是一個優先事項,您應該將帖子和修訂版存儲在一張表中。犧牲一點關係正確性來支持ORM範式的假設。

另一個建議是考慮Dimensional Modeling。這是一個支持OLAP和數據倉庫的數據庫設計學院。它明智地使用非規範化,所以您通常可以組織Star Schema中的數據。主要實體(「事實表」)由單個表格表示,所以這將是以ORM爲中心的應用程序設計的勝利。

+0

我想我寧願堅持兩張桌子。我認爲處理這個問題的最好方法是跳過'is_current'字段,並在文本表中包含每個條目的日期,以便我可以按修訂日期排序。或者等一下,那是行不通的,因爲我可能會想要保留一個修訂並恢復(需要一個'is_current'鍵)。也許一張表會更好,因爲作者,標題,文本和日期可能都會更改每個修訂版。再次,諸如評論/評論是否公開可能需要保持不變。 – Xeoncross 2010-01-01 18:00:48

+0

對,'is_current'的屬性與'date'無關。在關係數據庫設計中,值得將每個邏輯屬性存儲在單獨的列中。不要試圖讓列做雙重任務。 – 2010-01-01 18:08:05

+0

如果只使用一張表,你將如何使用主鍵?我想這不是依靠表格來增加行ID - 你將不得不取得最後一行的最後一個ID ... – Xeoncross 2010-01-19 02:00:49

0

你可能會是在這種情況下,最好穿上後您的表CurrentTextID以避免找出哪個版本是最新的(替代將是對修訂版的標誌,但我認爲一個CurrentTextID在帖子上會讓你更容易查詢)。

使用Post上的CurrentTextID,您的ORM應該在您的Post類中放置一個屬性(CurrentText),它允許您使用您提供的語句訪問當前文本。

你的ORM還應該給你一些方法來加載基於帖子的修訂;如果你想了解更多的細節,那麼你應該包含你正在使用哪個ORM以及你如何配置的信息。

+0

那麼到底是什麼,我不知道,這將有助於速度的東西了很多,因爲我也可以只'ORDER BY日期DESC,LIMIT 1 '通過修訂表獲取發佈文本時。 – Xeoncross 2009-12-28 16:38:05

+0

如果您一次抓取多個帖子(例如,如果您想顯示最近的10個帖子),則使用LIMIT並不容易。無論如何,如果這不是你正在尋找的東西,那又怎麼樣? – 2009-12-28 20:00:49

+0

我正在談論使用'$ post-> text-> body'並讓它自動創建SQL以使用'ORDER BY date'子句獲取最新版本。無論如何,我並不在乎它是如何完成的,我只想要一個已經設置了修訂系統的人來告訴我他們是如何做到的(即使用的表格,模型關係等)。 – Xeoncross 2009-12-30 16:56:35

0

我認爲兩張表就足夠了。帖子表和它的修訂版。如果您不擔心重複數據,則可以使用單個表(非標準化)。

+0

嗯,我試圖通過使用直通表遵循適當的3NF +練習。 http://en.wikipedia.org/wiki/Database_normalization 但是,你的權利,只是使用兩個表更容易 - 在我的情況下,我不知道會有「修訂」表的好處無論如何。 – Xeoncross 2009-12-30 20:37:51

+0

那麼你必須在表格之間移動數據? – AnApprentice 2009-12-30 23:08:09

0

對於任何有興趣的人,這裏是wordpress如何使用單個MySQL帖子表處理修訂。

CREATE TABLE IF NOT EXISTS `wp_posts` (
    `ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 
    `post_author` bigint(20) unsigned NOT NULL DEFAULT '0', 
    `post_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', 
    `post_date_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', 
    `post_content` longtext NOT NULL, 
    `post_title` text NOT NULL, 
    `post_excerpt` text NOT NULL, 
    `post_status` varchar(20) NOT NULL DEFAULT 'publish', 
    `comment_status` varchar(20) NOT NULL DEFAULT 'open', 
    `ping_status` varchar(20) NOT NULL DEFAULT 'open', 
    `post_password` varchar(20) NOT NULL DEFAULT '', 
    `post_name` varchar(200) NOT NULL DEFAULT '', 
    `to_ping` text NOT NULL, 
    `pinged` text NOT NULL, 
    `post_modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', 
    `post_modified_gmt` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', 
    `post_content_filtered` text NOT NULL, 
    `post_parent` bigint(20) unsigned NOT NULL DEFAULT '0', 
    `guid` varchar(255) NOT NULL DEFAULT '', 
    `menu_order` int(11) NOT NULL DEFAULT '0', 
    `post_type` varchar(20) NOT NULL DEFAULT 'post', 
    `post_mime_type` varchar(100) NOT NULL DEFAULT '', 
    `comment_count` bigint(20) NOT NULL DEFAULT '0', 
    PRIMARY KEY (`ID`), 
    KEY `post_name` (`post_name`), 
    KEY `type_status_date` (`post_type`,`post_status`,`post_date`,`ID`), 
    KEY `post_parent` (`post_parent`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ; 
+0

哇 - 爲什麼在世界上他們會使用VARCHAR(255)作爲guid? – 2010-01-19 02:18:59