PHP обновляет отношение MYSQL "многие ко многим"


У меня есть отношение "многие ко многим", реализованное с помощью таблицы ассоциаций в MySQL. У меня есть стол для детей и стол для родителей. У ребенка может быть несколько родителей, сохраненных в таблице ассоциаций parent_child_link с их идентификаторами.

Дети могут быть обновлены с помощью HTML-формы, родители находятся в HTML-множественном выборе. Теперь мне нужно обновить запись в базе данных, но мое решение не очень эффективно. Вот в псевдокоде, что я делаю:

  1. Обновите ребенка информация, где child_id=x
  2. Удалите все текущие ассоциации в parent_child_link, где child_id=x
  3. Вставьте новые ассоциации

Это решение отлично работает, но когда родители не были изменены, например, было изменено только имя ребенка, то выполняется 2 ненужных запроса. Как я могу избежать этих ненужных запросов? Есть ли какой-нибудь способ проверить, не изменились ли родители в множественном выборе?

Конечно, я мог бы просто проигнорировать все это хлопот, потому что это уже работает, но мне действительно нравится, чтобы все было максимально эффективно.

Author: EsTeGe, 2012-05-05

4 answers

Попробуйте решить ее в базе данных, а не на прикладном уровне, используя ON UPDATE CASCADE и ON DELETE CASCADE в определении дочерней таблицы.

Слегка переработанный пример с сайта MySQL:

CREATE TABLE parent (id INT NOT NULL,
                     PRIMARY KEY (id)
) ENGINE=INNODB;

CREATE TABLE child (id INT, parent_id INT,
                    INDEX par_ind (parent_id),
                    FOREIGN KEY (parent_id) REFERENCES parent(id)
                      ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=INNODB;

Ознакомьтесь с документами здесь: http://dev.mysql.com/doc/refman/5.5/en/innodb-foreign-key-constraints.html

ИЗМЕНИТЬ: Для вашего отношения "многие ко многим" вы можете использовать что-то вроде:

CREATE TABLE parent_child_link (
                    parent_id INT NOT NULL,
                    child_id INT NOT NULL,
                    PRIMARY KEY(parent_id, child_id),
                    FOREIGN KEY (parent_id) REFERENCES parent(id)
                      ON DELETE CASCADE ON UPDATE CASCADE,
                    FOREIGN KEY (child_id) REFERENCES child(id)
                      ON DELETE CASCADE ON UPDATE CASCADE
);

Надеюсь, это поможет.

 0
Author: John P, 2012-05-05 13:54:02

У меня тот же вопрос, и я нашел свое решение, когда читал.

Когда я буду готов обработать отправленные записи, я сначала выполню запрос, чтобы получить текущие ассоциации и вызвать этот массив $original_list. Представленный список я буду называть $submitted_list.

$original_list = array(3,5,7);
$submitted_list = array(1,2,3);

Тогда мне просто нужно выяснить 1) какие элементы удалить (больше не существуют) и 2) какие элементы добавить (новые ассоциации). Элементы в обоих списках не затрагиваются.

$delete_list = array_diff($original_list, $submitted_list);
$insert_list = array_diff($submitted_list, $original_list);

foreach($delete_list as $item) {
    // delete $item from DB
}

foreach($insert_list as $item) {
    // insert item in db
}

Хотелось бы знать, если другие считают это правильным решением.

 8
Author: Thom, 2012-06-05 15:42:59

Ваше решение прекрасно.
В вашем случае вы могли бы "оптимизировать" процесс, сделав запрос для получения родителей и сверившись с данными множественного выбора, произошли ли какие-либо изменения.
Затем вы выполняете только два запроса на удаление и вставку, если это необходимо. Аналог заключается в том, что когда вы на самом деле изменили родителей, вместо 2 запросов будет 3.
Поэтому вам следует спросить себя, часто ли вы собираетесь изменять родителей. В этом случае вы должны придерживаться своего оригинальное решение, позволяющее избежать дополнительного запроса на выбор.
Если вы думаете, что родители не будут обновляться очень часто, то вы можете воспользоваться вышеприведенным решением. Когда вы обновляете только информацию о ребенке, выполняется только один запрос. Когда вы также обновляете родителей, выполняется 3 запроса.
Когда вы переходите ко второму решению, запросы на удаление и вставку также можно оптимизировать, чтобы выполнять только то, что требуется (удалять только родителей, которые больше не являются его родителями, и вставлять только новых родителей ссылки).
Функции массива PHP могут быть полезны для этого.

 0
Author: florian, 2012-05-05 13:55:07

Если вы хотите сохранить свой текущий способ выполнения, но просто оптимизировать, вы можете обернуть запросы в операторы IF.

Например:

if ( isset ( $parent_name_change )){ // run query }

 0
Author: Kao, 2012-05-06 13:47:57