2-table interaction: insert, get result, insert

喜夏-厌秋 提交于 2019-12-11 01:53:49

问题


I need to make a fundamental decision of my database/web interaction and I am missing the knowledge to even find proper search terms.

Background:

I am building a family website which supports a forum, family tree, pvp games with rankings and more details, all from a datamodel. Technologies right now: Php, MySQL, javascript in object oriented fashion.

Requirement:

In a forum datamodel, process a written post as addition of a new forum topic (thread).

Current approach:

In my current datamodel this would imply and update on two tables: Post and Topic. I would need to insert a row in the topic table, then get the newly generated topicId(sequence), and then use that in an insert to the post table.

Problem:

I feel this is too much work for what needs to happen, too much interaction. But it will become a typical requirement if I stick with the current approach.

Question:

  1. am I on the right track anyway or should I
  2. restructure the datamodel or
  3. pick another way of database interaction (e.g. stored procedures)
  4. am I facing a typical example where you would use methodology/framework xyz.

Currently tables have following structure (loosely based on this one from erdiagrams.com)

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

POST

id
topic_id(FK)
person_id(FK)
subject
message
timestamp
replyto

Then I have a view that collects the last post for each topic and displays some info on that as well (e.g. last poster image) over the trigger Tc_post_id.


回答1:


Ad 1 and 2: Your data model is fine. Using foreign keys is crucial here. One more thing that you need to take care of is that the database should ensure there is a TOPIC record for each POST. This is done by setting POST.topic_id NOT NULL attribute. This is sufficient safety mechanism on the DB side, as it ensures that no POST will be left without TOPIC. No matter what you do now with your POST you are obligated to provide a TOPIC.

Ad 3: A trigger with stored procedure is not recommended here as you have additional data in your TOPIC table (IsSticky, IsLocked, etc), which you might want to provide upon TOPIC record creation. Also, if such a trigger would be applicable, the database design would be a subject to denormalization.

Ad 4: On the business logic side you can now aid yourself by writing a automated mechanism to create the TOPIC record every time a new POST record is created without specified topic_id. I recommend using some ORM for this or take advantage of the data models available in any MVC framework. The blueprint for such models would look like this:

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;
    }

    // ...
}

Note: as a good MVC practice those models should be the only place to directly operate on the table rows. Otherwise you'll end up getting SQL errors (but the data model will remain coherent, so you don't have to worry that something will break).

Finally take advantage of your models in the controller layer:

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
        }
    }
}



回答2:


The way I understand it: topics are containers of posts.

Topics table would be rather minimal, and would perhaps only contain a topic id (PK) and topic title.

The posts themselves will contain post id (PK), topic id (FK), timestamps, author id, text.

I would utilize InnoDB and foreign keys, so a topic that is deleted could delete all of its child posts.




回答3:


(edit:) In this answer I posted a way to do it using mysql_insert_id(), which would be still a technically correct solution (correct me if wrong).

However instead I will now go for the PDO wrapper I guess. And also, this is not an answer to the general modeling/approach question.

Still, following would be a way to do it:

$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);

Source: http://www.desilva.biz/mysql/insertid.html



来源:https://stackoverflow.com/questions/13905381/2-table-interaction-insert-get-result-insert

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!