Mysql
 sql >> Base de données >  >> RDS >> Mysql

Interaction à 2 tables :insérer, obtenir un résultat, insérer

Annonces 1 et 2 :votre modèle de données est correct. L'utilisation de clés étrangères est cruciale ici. Une autre chose dont vous devez vous occuper est que la base de données doit s'assurer qu'il existe un enregistrement TOPIC pour chaque POST. Cela se fait en définissant POST.topic_id NOT NULL attribut. Il s'agit d'un mécanisme de sécurité suffisant du côté de la base de données, car il garantit qu'aucun POST ne sera laissé sans TOPIC. Peu importe ce que vous faites maintenant avec votre POST, vous êtes obligé de fournir un SUJET.

Annonce 3 :Un déclencheur avec procédure stockée n'est pas recommandé ici car vous avez des données supplémentaires dans votre table TOPIC (IsSticky, IsLocked, etc.), que vous voudrez peut-être fournir lors de la création de l'enregistrement TOPIC. De plus, si un tel déclencheur était applicable, la conception de la base de données serait sujette à dénormalisation.

Annonce 4 :Du côté de la logique métier, vous pouvez désormais vous aider en écrivant un mécanisme automatisé pour créer l'enregistrement TOPIC chaque fois qu'un nouvel enregistrement POST est créé sans topic_id spécifié. Je recommande d'utiliser certains ORM pour cela ou de profiter des modèles de données disponibles dans n'importe quel framework MVC. Le plan de ces modèles ressemblerait à ceci :

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

    // ...
}

Remarque :en tant que bonne pratique MVC, ces modèles doivent être le seul endroit où opérer directement sur les lignes de la table. Sinon, vous finirez par avoir des erreurs SQL (mais le modèle de données restera cohérent, vous n'avez donc pas à craindre que quelque chose se casse).

Profitez enfin de vos modèles dans le contrôleur calque :

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