Какое-нибудь элегантное решение, как сделать вставку во многие ко многим таблицам? - PullRequest
3 голосов
/ 12 июля 2011

Я получил эти таблицы:

  • Tag - содержит имена и идентификаторы тегов (Tag_ID, tag)
  • TagReview - связывание таблицы между тегами и отзывами (Review_ID, Tag_ID)
  • Отзыв - содержит отзывы. (Review_ID, содержание, ...)

В настоящее время я сделал вставки, когда обзор добавлен или отредактирован. В моей таблице тегов класс расширяется от Zend_DB_Table ... В некоторых случаях вставка работала, но затем произошла ошибка с ошибкой sql «SQLSTATE [23000]: нарушение ограничения целостности: 1452»

    public function insertTags($reviewId, $tagList) {
    $reviewTag = new Application_Model_DbTable_ReviewTag;
    $tags = explode(self::SEPERATE, $tagList);

    foreach ($tags as $tag) {
        $tag = trim($tag);
        $tagRow = $this->fetchRow(array('tag = ?' => $tag));
        if ($tagRow == null) {
            $tagId = $this->insert(array(
                'tag' => trim($tag)
            ));
            $reviewTag->insert(array(
                'Tag_ID'        => $tagId,
                'Review_ID'     => $reviewId,       
            ));
        }

    }
}

Ответы [ 2 ]

0 голосов
/ 19 августа 2011

Я решил свое решение по этому коду.Также решает проблему, если при редактировании теги были удалены или добавлены.

/**
 * Insert the tags.
 * @param reviewId int review which the tags belongs.
 * @param tagList string tags with seperated coma or space.
 */
public function insertTags($reviewId, $tagList) {
    // The join table to solve many-to-many relation
    $reviewTag = new Review_Model_DbTable_ReviewTag;
    $tags = explode(self::SEPERATE, $tagList);

    // Go through all the tags
    foreach ($tags as $tag) {
        $tag = trim($tag);

        // Check if already in Tag table
        $tagRow = $this->fetchRow(array('tag = ?' => $tag));
        if ($tagRow == null) {
            // It's new tag create new tag
            $tagId = $this->insert(array(
                'tag'               => trim($tag)
            ));
            // Add the the id's to join table
            $reviewTag->insert(array(
                'Tag_ID'            => $tagId,
                'Review_ID'         => $reviewId,       
            ));
        } else {
            // Tag is already in database use the id and check the uniquness
            $unique = $reviewTag->fetchRow(array(
                'Review_ID = ?'     => $reviewId, 
                'Tag_ID = ?'        => $tagRow->Tag_ID
            ));
            if ($unique == null) {
                $reviewTag->insert(array(
                    'Tag_ID'        => $tagRow->Tag_ID,
                    'Review_ID'     => $reviewId,                       
                ));
            }

        }
    }
    $this->deleteTags($tags, $this->getOnlyTags($reviewId), $reviewId);
}

/**
 * Delete tags from table which are listed in $tags array.
 * @param mixed $tags array
 * @param mixed $userInserted array
 * @param int $reviewId 
 */
public function deleteTags($tags, $userInserted, $reviewId) {
    $diffTags = array_diff($tags, $userInserted);
    $reviewTag = new Review_Model_DbTable_ReviewTag;

    foreach ($diffTags as $tag) {
        $tagId = $this->fetchRow(array('tag = ?' => $tag))->Tag_ID;
        $reviewTag->delete(array(
            'Review_ID = ?' => $reviewId,
            'Tag_ID = ?'    => $tagId,
        ));
    }
}
/**
 * Get the tags names related to review.
 * @param reviewId int review id
 * @return array name of the tags as string
 */
public function getOnlyTags($reviewId) {
    $tags = array();
    $reviewTags = $this->fetchTags($reviewId);
    foreach ($reviewTags as $reviewTag) {
        $tags[] = $reviewTag->tag;
    }
    return $tags;
}
0 голосов
/ 19 августа 2011

так что проблема в следующем:

"SQLSTATE[23000]: Integrity constraint violation: 1452"

Если бы мне пришлось делать догадки без трассировки стека, я бы сказал, что следующая строка - это проблема: </p> <pre><code>$tagId = $this->insert(array( 'tag' => trim($tag) ));

Я предполагаю, что у вас есть уникальное ограничение на вашу таблицу тегов, чтобы гарантировать, что дубликаты тегов не будут добавлены в таблицу.

Проблема в том, что эта строка не должна быть вставкой, это должна быть getTagIDByTag и, если это не так, вставка. ТАК, </p> <pre><code>public function insertTags($reviewId, $tagList) { $reviewTag = new Application_Model_DbTable_ReviewTag; $tags = explode(self::SEPERATE, $tagList); foreach($tags as $tag) { $tag = trim($tag); $tagRow = $this->fetchRow(array('tag = ?' => $tag)); if($tagRow == null) { // FIRST TRY TO GET THE TAG $tagId = $db->fetchCol('SELECT Tag_ID FROM Tag WHERE tag = ?', trim($tag)); // ZEND RETURNS NULL IF THE QUERY DOESN'T RETURN ANYTHING if(is_null($tagId)) { // CREATE THE TAG $tagId = $this->insert(array( 'tag' => trim($tag) )); } $reviewTag->insert(array( 'Tag_ID' => $tagId, // USE THE TAG ID LIKE NORMAL 'Review_ID' => $reviewId, )); } } }

...