#5 Практическое задание №5 -- связь "многие ко многим" (много статьей и у каждой несколько авторов)
Primary tabs
В одном из предыдущих заданий, мы добавили возможность создавать учетные записи пользователей в базе данных, также у нас имеется сущность "Статья". Теперь добавим возможность в админке для каждой статьи указать автора причем не обязательно одного, а, возможно, и сразу нескольких.
Таким образом мы научимся работать связью "Многие ко многим".
Для этого:
- Пишем запрос, добавляющий таблицу связи -- в ней два "технических" поля -- одно указывает на id статьи а другое на id пользователя (оба внешние ключи). (подумайте, что можно тут сделать первичным ключом)
- Далее в форму редактирования статьи добавьте выпадающий список, где в качестве значения каждого пункта используется id пользователя, а в в качестве текста пункта -- логин пользователя, сделайте выбор этого селектбокса множественным (чтобы прижав контрл можно было выбрать сразу нескольких авторов).
- Log in to post comments
- 53023 reads
JinJim
Sat, 02/24/2018 - 15:51
Permalink
готово
https://github.com/kdn2517/my-first-cms-...
vedro-compota
Sat, 02/24/2018 - 16:52
Permalink
замечания
замечания:
-- эти поля лучше называть по смыслу, например:
_____________
матфак вгу и остальная классика =)
JinJim
Sun, 02/25/2018 - 05:34
Permalink
ответ
1. На движке MyISAM быстрее работают операции INSERT и SELECT, а они преобладают в этой таблице.
Меняю движок:
ALTER TABLE users_articles engine=InnoDB;
2. Устанавливаю связи:
ALTER TABLE `users_articles` ADD INDEX( `user`);
ALTER TABLE `users` ADD UNIQUE( `id`);
ALTER TABLE `users_articles` ADD INDEX( `article`);
ALTER TABLE `articles` ADD UNIQUE( `id`);
ALTER TABLE users_articles ADD FOREIGN KEY (user) REFERENCES users (id) ON DELETE RESTRICT ON UPDATE RESTRICT ;
ALTER TABLE users_articles ADD FOREIGN KEY (article) REFERENCES articles (id) ON DELETE RESTRICT ON UPDATE RESTRICT ;
vedro-compota
Sun, 02/25/2018 - 07:11
Permalink
На движке MyISAM быстрее
-- и главное, что есть полнотекстовый поиск, но нет транзакций -- что очень важно. По-умолчанию используйте InnoDB -- тем более что там тоже у есть полнотекстовый поиск.
_____________
матфак вгу и остальная классика =)
JinJim
Sun, 02/25/2018 - 07:12
Permalink
ok
ok
vedro-compota
Tue, 02/27/2018 - 14:34
Permalink
разметка мардаун
Просьба разметить весь код в README.md формате маркдаун (в частности это касается кода SQL-запросов) чтобы не был просто текст https://github.com/kdn2517/my-first-cms-...)
_____________
матфак вгу и остальная классика =)
vedro-compota
Tue, 02/27/2018 - 14:47
Permalink
уточним алгоритм
JinJim, опишите на русском ваш алгоритм (несколько шагов) извлечения статьи по id вместе с авторами -- вам как минимум нужен массив их имен, но я что-то не пойму как вы его извлекаете, используя таблицу связи.
_____________
матфак вгу и остальная классика =)
JinJim
Tue, 02/27/2018 - 15:08
Permalink
попробую:
1. В конструктор Article я передаю вторым параметром массив всех связей (по сути всю таблицу, которую извлекаю в getList).
2. В конструкторе обычным перебором массива сравниваю значения id статьи и значения из таблицы связи, если они совпадают - добавляю в массив.
Могу поподробней - со ссылками попробовать объяснить.
vedro-compota
Tue, 02/27/2018 - 15:14
Permalink
перевести на join
не надо. понял. Тогда надо переделать необходимо извлекать авторов для каждой статьи используя JOIN (соединение таблиц) (в реальной проекте у тебя могут быть миллионы связей - нельзя вытаскивать всё каждый раз)
_____________
матфак вгу и остальная классика =)
JinJim
Wed, 02/28/2018 - 21:01
Permalink
Вопрос
Ознакомился с оператором JOIN, может быть я чего-то не понимаю, но на мой взгляд в данном конкретном случае его не нужно использовать. Объясню свою логику: для вывода всех статей к
добавляем JOIN, получим что-то вроде этого:
На сколько я понимаю как результат мы получаем таблицу, где данные из таблицы articles повторяются столько раз, сколько авторов у статьи (а если авторов 10, а статьи огромные не нагрузит ли это сервер?). Не проще ли сделать два запроса? Для вывода всех статей в любом случае нам нужны обе таблицы целиком, а для вывода статей определенного автора у меня стоит условие.
vedro-compota
Fri, 03/09/2018 - 19:48
Permalink
t1 -- таблица связи?
-- что такое t1? Если это таблица связи, то логичнее (и намного понятнее, что важно) было бы назвать её articles_users.
Рекомендую ознакомиться с частью "извлечение данных" вот здесь: http://fkn.ktu10.com/?q=node/9983
_____________
матфак вгу и остальная классика =)
JinJim
Sat, 03/10/2018 - 13:42
Permalink
Я понял как работает оператор JOIN, но вопрос остался
t1 это таблица связи, я ее так и назвал - users_articles:
Да, действительно можно использовать JOIN:
Как результат мы получаем таблицу, где данные из таблицы articles повторяются столько раз, сколько авторов у статьи (а если авторов 10, а статьи огромные это нагрузит сервер). Проще сделать два запроса. Для вывода всех статей в любом случае нам нужны обе таблицы целиком, а для вывода статей определенного автора у меня стоит условие.
В крайнем случае, если у нас действительно миллион связей, а нужно вывести 5 статей, то можно взять сделать первый запрос (который был у нас), забрать там id статей и по ним сделать второй запрос в таблицу связи, потом так же массивом передать в конструктор. В результате получим два небольших компактных запроса вместо одного мега-запроса (данные из которого еще и обрабатывать придется).
vedro-compota
Mon, 03/12/2018 - 10:20
Permalink
id пользователя в таблице связи?
а t1.user -- это id пользователя в таблице связи? лучше называть "как есть", чтобы не было догадок, те.е не user а user_id (при создании схемы таблицы)
_____________
матфак вгу и остальная классика =)
vedro-compota
Mon, 03/12/2018 - 10:50
Permalink
JOIN: с таблицей связи и таблицей присоединённой сущности
Сервер такой подход не нагрузит особо -- если авторов 10, но вот если это другая ситуация и в табилце связи для данной сущности этих "многих" --миллионы, то да -- дублирование данных приведёт к тому, что ответ СУБД будет попадать в приложение не быстро.
Но есть и другая проблема, запрос:
Не только дублирует извлекаемые данные, но и не получает сразу всех информации о "присоединенных" сущностях, дело в том, что необходимо делать join не с таблицей связи и данной сущностью, а с таблицей связи и таблицей присоединённой сущности, учитывая ограничение (напр. на id данной сушности) -- как это сделано в статье (см. "извлечение данных" для 1 сущности) и также можно глянуть пояснение на видео: https://youtu.be/XKEwmJR4rHk
_____________
матфак вгу и остальная классика =)
JinJim
Tue, 03/13/2018 - 12:27
Permalink
Исправил
Спасибо за подробное объяснение, а то у меня этот GROUP BY прямо мимо ушей проходил)) Как то так:
Это запрос:
Это на github:
https://github.com/kdn2517/my-first-cms-...
Все работает, а главное это действительно проще, причем как в плане кода так и в плане нагрузки на сервер.
sid
Sat, 02/24/2018 - 21:14
Permalink
Вопрос нужно ли перестраивать
Вопрос нужно ли перестраивать таблицу users, ведь там у нас вместо id, которое должно быть primary key, служит поле login, которое unique index.
vedro-compota
Sun, 02/25/2018 - 06:58
Permalink
нужно ли перестраивать
всё-таки грамотнее перестроить, хотя конечно, можно и на текстовый ключ ссылаться текстовым значением же -- но это занимает больше памяти.
_____________
матфак вгу и остальная классика =)
sid
Tue, 02/27/2018 - 14:12
Permalink
С таблицей более менее
С таблицей более менее понятно, теперь встает вопрос как это обрабатывается на уровне классов, ведь теперь у нас новая таблица, которую нужно обработать со стороны двух классов user и articles?
vedro-compota
Tue, 02/27/2018 - 14:29
Permalink
если кратко
Если кратко:
_____________
матфак вгу и остальная классика =)
sid
Tue, 02/27/2018 - 16:49
Permalink
И все же я пока не совсем
И все же я пока не совсем понимаю, как это все связать, откуда попадают данные в связную таблицу и как их туда записать?
vedro-compota
Tue, 02/27/2018 - 19:12
Permalink
сохранение данных -- возможный подход работы с таблицей связи
возможный алгоритм
- при данном подходе обновление редактируемой сущности обеспечивается тремя SQL запросами:
-- для того, чтобы обновление гарантированно прошло целиком (или не прошло вообще -- лишь бы не частично) -- оберните в транзакцию, код работающий с базой (обеспечивающий все три запроса)
_____________
матфак вгу и остальная классика =)
sid
Wed, 02/28/2018 - 20:27
Permalink
Прошу привести конкретный
Прошу привести конкретный пример, т.к для меня это пока не просто дается
sid
Wed, 03/14/2018 - 14:59
Permalink
Прошу посмотреть пример
Прошу посмотреть пример
vedro-compota
Fri, 03/09/2018 - 20:00
Permalink
Посмотрим чисто SQL-ный пример
sid, смотрите:
-- используя этот алгоритм вы должны просто сделать вставку id сущностей в таблицу связи после того, как форма сохранения статьи пришла на сервер, для этого вам надо выполнить сначала INSERT для полей статьи, а потом INSERT в таблицу связи -- и то и то присутствует например в коде разворота примера
Ознакомьтесь с примером и выполните задания: http://fkn.ktu10.com/?q=comment/2282#com...
-- если там все будет понятно, то вернёмся к этому обсуждению.
_____________
матфак вгу и остальная классика =)
Pavel1989
Sat, 09/07/2019 - 13:47
Permalink
Практическое задание №5:
Выполнено.
Коммит
dimmkan
Sat, 11/02/2019 - 18:44
Permalink
Практическое задание №5
Ссылка на коммит
NewDeveloper
Thu, 02/03/2022 - 15:00
Permalink
Практическое задание №5
Изменение 5