我需要对我的数据库/网络互动作出基本决定,我甚至错过了找到合适搜索字词的知识。
我正在建立一个家庭网站,它支持一个论坛,家谱,带有排名和更多细节的PVP游戏,所有这些都来自数据模型。现在的技术:面向对象的Php,MySQL,javascript。
在论坛数据模型中,处理书面帖子作为新论坛主题(线程)的添加。
在我当前的数据模型中,这将暗示并更新两个表:Post和Topic。 我需要在主题表中插入一行,然后获取新生成的topicId(序列),然后在插入表格中使用它。
对于需要发生的事情,过多的互动,我觉得这是太多的工作。 但如果我坚持当前的做法,它将成为一个典型的要求。
问题:
目前表格有以下结构(松散地基于erdiagrams.com的this one)
TOPIC :('thread')
id
Forum_ID (FK)
Person_ID (FK)(threadcreator)
IsLocked
IsSticky
Subject
ViewCount
DateCreated
Tc_post_id - trigger to last post_id in this thread
发表
id
topic_id(FK)
person_id(FK)
subject
message
timestamp
replyto
然后我有一个视图,收集每个主题的最后一篇文章,并在触发器Tc_post_id上显示一些信息(例如最后一张海报图片)。
答案 0 :(得分:1)
广告1和2:您的数据模型很好。在这里使用外键至关重要。您需要注意的另一件事是数据库应该确保每个POST都有一个TOPIC记录。这是通过设置POST.topic_id NOT NULL 属性来完成的。这是DB端的足够安全机制,因为它确保没有TOPIC就不会留下POST。无论你现在使用POST做什么,你都有义务提供一个主题。
广告3:此处不建议使用存储过程的触发器,因为您在TOPIC表(IsSticky,IsLocked等)中有其他数据,您可能希望在创建TOPIC记录时提供这些数据。此外,如果这样的触发器适用,数据库设计将成为非规范化的主题。
广告4:在业务逻辑方面,您现在可以通过编写自动机制来创建TOPIC记录,以便在没有指定topic_id的情况下创建新的POST记录。我建议使用一些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错误(但数据模型将保持连贯,所以你不必担心某些事情会破坏)。
最后利用 controller 层中的模型:
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
}
}
}
答案 1 :(得分:0)
我理解它的方式:主题是帖子的容器。
主题表格相当简洁,可能只包含topic id (PK)
和topic title
。
帖子本身将包含post id (PK)
,topic id (FK)
,timestamps
,author id
,text
。
我会使用InnoDB
和外键,因此删除的主题可能会删除所有子帖子。
答案 2 :(得分:0)
(编辑:) 在这个答案中,我发布了一种使用 mysql_insert_id()的方法,这仍然是技术上正确的解决方案(如果错误,请纠正我)。
然而我现在会选择PDO包装器。而且,这不是一般建模/方法问题的答案。
不过,以下是一种方法:
$sql = "INSERT INTO topic VALUES (NULL,'$forumId',<more parameters>)";
$result = mysql_query($sql);
# get the generated id
$topicId = mysql_insert_id();
# and insert into the post table
$sql = "INSERT INTO post VALUES (NULL,'$topicId',<more parameters>)";
$result = mysql_query($sql);
mysql_free_result($result);