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

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

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

  1. обновить данные ребенка, где ид_дочернего_объекта=х
  2. удалить все текущие ассоциации в parent_child_link, где child_id=x
  3. вставить новые ассоциации

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

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

4 ответов


попробуйте решить его в базе данных, а не на уровне приложения с помощью 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

EDIT: для вашего отношения "многие ко многим" вы можете использовать что-то вроде:

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

надеюсь, что это помогает.


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

когда я готов обработать отправленные записи, я сначала делаю запрос, чтобы получить текущие ассоциации и вызвать этот массив $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
}

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


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


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

Как:

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