广告 1 和 2:您的数据模型很好。在这里使用外键至关重要。您需要注意的另一件事是数据库应确保每个 POST 都有一个 TOPIC 记录。这是通过设置 POST.topic_id NOT NULL属性来完成的。这在 DB 端是足够的安全机制,因为它确保不会留下没有 TOPIC 的任何 POST。无论您现在对 POST 做什么,您都有义务提供一个主题。
广告 3:此处不建议使用带有存储过程的触发器,因为您的 TOPIC 表中有其他数据(IsSticky、IsLocked 等),您可能希望在创建 TOPIC 记录时提供这些数据。此外,如果这样的触发器适用,则数据库设计将成为非规范化的主题。
广告 4:在业务逻辑方面,您现在可以通过编写一个自动化机制来帮助自己,每次创建一个没有指定 topic_id 的新 POST 记录时创建 TOPIC 记录。我建议为此使用一些 ORM,或者利用任何 MVC 框架中可用的数据模型。此类模型的蓝图如下所示:
abstract class AModel // this class should be provided by ORM or framework
{
/**
* @var PDO
*/
protected $_db_driver;
public function getLastInsertId()
{
$stmt = $this->_db_driver->prepare('SELECT LAST_INSERT_ID() AS id');
$stmt->execute();
return $stmt->fetch(PDO::FETCH_OBJ)->id;
}
public abstract function getFieldList();
}
class ForumTopicModel extends AModel
{
public function insert(array $data)
{
$sql = 'INSERT INTO topic VALUES (:id, :forum_id, :person_id, :is_locked, ...)';
$stmt = $this->_db_driver->prepare($sql);
return $stmt->execute($data);
}
public function getFieldList()
{
return array('id', 'forum_id', 'person_id', 'is_locked', /*...*/);
}
// ...
}
class ForumPostModel extends AModel
{
public function insert(array $data)
{
$sql = 'INSERT INTO post VALUES (:id, :topic_id, :person_id, :subject, ...)';
$stmt = $this->_db_driver->prepare($sql);
return $stmt->execute($data);
}
public function getFieldList()
{
return array('id', 'topic_id', 'person_id', 'subject', /*...*/);
}
public function insertInitialTopicPost(array $form_data)
{
$this->_db_driver->beginTransaction();
$result = true;
if ( empty($form_data['topic_id']) ) {
// no topic_id provided, so create new one:
$topic = new ForumTopicModel();
$topic_data = array_intersect_key(
$form_data, array_flip($topic->getFieldList())
);
$result = $topic->insert($topic_data);
$form_data['topic_id'] = $topic->getLastInsertId();
}
if ( $result ) {
$forum_post_data = array_intersect_key(
$form_data, array_flip($this->getFieldList())
);
$result = $this->insert($forum_post_data);
}
if ( $result ) {
$this->_db_driver->commit();
}
else {
$this->_db_driver->rollBack();
}
return $result;
}
// ...
}
注意:作为一种良好的 MVC 实践,这些模型应该是唯一可以直接对表行进行操作的地方。否则,您最终会遇到 SQL 错误(但数据模型将保持一致,因此您不必担心会出现问题)。
最后利用控制器层中的模型:
class ForumPostController extends AController
{
public function createInitialTopicPostAction()
{
$form_data = $this->getRequest()->getPost(); /* wrapper for getting
the $_POST array */
// (...) validate and filter $form_data here
$forumPost = new ForumPostModel();
$result = $forumPost->insertInitialTopicPost($form_data);
if ( $result ) {
// display success message
}
else {
// display failure message
}
}
}