|
9 / 6 / 3
Регистрация: 10.01.2020
Сообщений: 330
|
||||||||||||||||||||||||||||||||||||
MySQL Как сделать оптимальный код для вставки строк (INSERT and FOREIGN KEY) (linq2db)17.02.2021, 15:55. Показов 8392. Ответов 27
Доброго всем!
Когда мелкое приложение, которое использует БД с парой таблиц, вопросов не возникает. А когда приложение по крупнее, нужна правильно спроектированная БД. Вот с самой проектировкой БД более-меннее понятно. Но вопросов много возникает при вставке новых значений в таблицы с внешними ключами (FOREIGN KEY). Все видеокурсы о SQL на 90+% состоят из уроков на SELECT. В этих курсах или данные уже существуют, до начала урока, и делаются выборки, или добавляются данные с уже известными внешними ключами. Но как оптимально поступать в реальных приложениях? Это всё естественно примитивная модель БД, чтобы лучше объяснить что я хочу. Мне нужно не создать структуру БД, а понять "правильный"|"оптимальный"|"лёгкий"|"над ёжный" способ работы с БД из .Net + linq2db и FOREIGN KEY. Представьте вот такую ситуацию. Есть некий сервис онлайн курсов "Online". К нему есть ограниченный доступ по API (по 1 разу в 60 минут к Student и Course). Tеоретически я хочу получать актуальную информацию с сервиса и добавлять её в свою БД, чтобы все желающие могли использовать эту информацию без ограничений. Чтобы не было многабукаф, спрячу код под спойлеры. Сущности получаемые по API
Из двух API объектов Student и Course получается три таблицы в БД, так как один студент может быть записан на несколько курсов. `StudentCourse` таблица многие ко многим. У одного студента может быть много курсов. У одного курса можеть быть много студентов. SQL создания таблиц
Соответственно для этих таблиц БД созданы классы-сущности в C# Сущности C# для linq2db
А теперь последовтельность действий. Я могу сделать запрос и получить список пользователей (Online.API.Student -- get.Student?) И получить объекты класса Online.API.Student. К примеру получаю вот такого пользователя.
Затем я конвертирую его в Online.Model.Student и добавляю в таблицу БД `Student`
И вот теперь мне нужно добавить данные в таблицу `StudentCourse`. Но есть несколько вопросов. Я не могу добавить с обновлением потому, что в таблице стоит PrimaryKey на оба поля. А так же я не знаю существует ли Course.Id в таблице `Course`. То есть мне нужно проверить существование Course.Id, затем отсутствие этой пары в `StudentCourse`. С этого места мне кажетя всё идёт не очень гладко. Может и до этого места тоже было не очень, но сейчас и я это вижу. Реализация вставки. С предварительной проверкой вставляем строки
И только теперь добавляем в таблицу, предварительно проверив на существование.
Вопрос вот собственно в чём. При каждом обновлении Student, мне нужно совершать кучу этих запросов. Как вообще опытные разработчики с этим поступают? Я думаю должен быть способ это сделать проще. Допустим сам ORM linq2db может что-то уже умеет делать это проще? P.S. Сразу получить все курсы с API я не могу. (Online.API.Course) Могу получать только пользоватлелей, и уже потом по CourseIds получать описание и всё остальное по самому курсу. Буду благодарен за любую помощь. Конструктивная критика, с указанием на ошибки, и способы их решений крайне приветствуется.
0
|
||||||||||||||||||||||||||||||||||||
| 17.02.2021, 15:55 | |
|
Ответы с готовыми решениями:
27
Как сделать Insert в таблицу, которая содержит foreign key другой таблицы SQLite - оптимальный размер транзакции, стоит ли использовать FOREIGN KEY, связь PRIMARY KEY и INDEX Insert запрос к sqlite с foreign key |
|
14291 / 9376 / 1352
Регистрация: 21.01.2016
Сообщений: 35,331
|
|||||||
| 17.02.2021, 17:08 | |||||||
Второй вариант - оптимистичный вариант работы с курсами. Мы ничего не проверяем, а просто добавляем (на пофиг) связь студента и курса. Если получаем исключение, то добавляем курс. СУБД один же чёрт производит проверку существования записей на которые внешние ключи ссылаются. Второй раз явно это делать смысла не особо много)
1
|
|||||||
|
9 / 6 / 3
Регистрация: 10.01.2020
Сообщений: 330
|
|||||||||||||
| 17.02.2021, 17:40 [ТС] | |||||||||||||
|
Получить всю таблицу БД в ОЗУ и работать уже с ней?
0
|
|||||||||||||
|
|
|||||
| 17.02.2021, 19:08 | |||||
|
1
|
|||||
|
9 / 6 / 3
Регистрация: 10.01.2020
Сообщений: 330
|
||||||||
| 17.02.2021, 20:17 [ТС] | ||||||||
Я не про корявость своих запросов, я про сам подход, что нужно получать отдельным запросом внешние ключи и проверять их наличие в БД пусть это hashset или dictionary или ещё чем нибуть? Но никаких обходных путей ни БД ни ORM не даёт? То есть одним запросом не получится добавить строку, и отсутствующие внешние ключи? И ещё что скажете по поводу хранимых процедур? Есть ли смысл их создавать для этих целей? Или не пытаться искать автоматизацию работы в FOREIGN KEY?
0
|
||||||||
|
|
|||||
| 17.02.2021, 21:55 | |||||
|
1
|
|||||
|
9 / 6 / 3
Регистрация: 10.01.2020
Сообщений: 330
|
|||
| 17.02.2021, 22:11 [ТС] | |||
|
На самом деле там больше и таблиц и связей и данных. Таблицы внешних ключей FOREIGN KEY надеюсь что за 5-10к не перевалят.
0
|
|||
|
|
||
| 17.02.2021, 22:25 | ||
Сообщение было отмечено BeginnerCoderCS как решение
РешениеНет ничего криминального даже отправить 100 EXISITS в базу данных, если у вас не высоконагруженное приложение с проблемами в производительности. Иногда простой понятный код намного важнее неоптимальных запросов к БД. PS: Преждевременная оптимизация — корень всех зол. (c) Д. Кнут.
1
|
||
|
1497 / 1238 / 245
Регистрация: 04.04.2011
Сообщений: 4,363
|
||||||
| 17.02.2021, 23:29 | ||||||
|
Студенты + Курсы + Многие-ко-многим.
Классический случай "Многие-ко-многим". Решается через кросс-таблицу:
Вы пытаетесь из лопаты соорудить какой-то синхрофазатрон. Логика CRUD для такой базы также примитивна. Перед записью в StudCurse проверяется есть ли такая парочка и дальше либо Insert либо Update. 10-15k форейнкеев ? И что ? А 15 млн не хотите ? 1000 запросов к базе в минуту ? А 1 млн не хотите ? И все никак не томозит если верно спроектировано. У Вас - не верно. Добавлено через 12 минут Linq2 за Вас не построит никакой логики. Совсем. Она просто избавит Вас от необходимости "ручками" писать все эти select, update, insert, delete. А всю "требуху" в виде семантической увязки таблиц в запросах, соблюдение целостности БД (транзакционность пакетов изменений), предварение исключений и т.д. надо писать "ручками" в виде класса-репозитория или как-Вы-там-его-назовете. Судя по всему, Вы не определились с самой бизнес-логикой СУБД, но уже лихо лепите таблицы, форейнкеи, праймари.. И уже озабочены "оптимизацией" Вашего велосипеда. С квадратными колесами, тремя рулями и без единого седла
0
|
||||||
|
14291 / 9376 / 1352
Регистрация: 21.01.2016
Сообщений: 35,331
|
|
| 18.02.2021, 05:46 | |
|
0
|
|
|
9 / 6 / 3
Регистрация: 10.01.2020
Сообщений: 330
|
|||
| 18.02.2021, 08:20 [ТС] | |||
|
Что конкретно предлагаете изменить? Чем отличается ваш SQL код от моего? Зачем вы добавили в таблицу многие-ко-многим Id? Какой смысл в этом?
0
|
|||
|
1497 / 1238 / 245
Регистрация: 04.04.2011
Сообщений: 4,363
|
||||
| 18.02.2021, 14:44 | ||||
|
Это - правило. Которое позволит избежать множества ошибок и костылей. Каждая таблица - сущность. В том числе кросс-таблица, каждая запись которой является отношением, связкой между другими сущностями. Это - азы СУБД.
0
|
||||
|
9 / 6 / 3
Регистрация: 10.01.2020
Сообщений: 330
|
||||||||
| 18.02.2021, 15:02 [ТС] | ||||||||
Первичный ключ у меня есть это (Student(SId) + Curse(CId)) и как раз не даёт добавлять уже имеющиеся пары. Добавлено через 2 минуты Что вы можете сделать в этой модели, чего не могу я в своей?
0
|
||||||||
|
1497 / 1238 / 245
Регистрация: 04.04.2011
Сообщений: 4,363
|
|||
| 18.02.2021, 17:12 | |||
|
Самое же главное в том, что при Вашем подходе если в базе не две сущности, а 50, то код работы с Вашей БД будет чрезмерно нагружен лишней логикой (вроде той, что в [5] и в [3]), которой бы не было при "классике". В целом же выбор за Вами, конечно. Можно ездить и без руля и сиденья. Подобных костыльных "баз" существует чуть больше, чем до фига. И многие работают ![]() Добавлено через 25 минут Поймите одну простую вещь. 1. Есть предметная область. 2. Есть сущности в этой предметной области. 3. У каждой сущности есть набор атрибутов: простых (атомарных) и сложных (тоже сущностей). 4. На атрибуты есть требования (тип данных, ограничения, уникальность..) 5. Сущности как-то связаны между собою определенными отношениями. На основании всего этого создается Модель СУБД. Абстрактная. В ней описывается (формализуется) система правил, которая образует бизнес-логику СУБД. Заметьте, пока ни слова ни про тип сервера, ни про какие-либо приложения. Сама бизнес-логика может быть реализована на SQL-сервере, где для этого есть чуть больше, чем все (роли, пользователи, хранимки, ограничения, триггеры, каскады, UDF, View, службы и т.д.). Преимущества такой имплиментации в том, что приложения, сколько бы их ни было, освобождены от подробностей Модели, они лишь дергают сервер за нужные "ниточки", их код краток и ясен. Плюс сервер будет работать шустро, не тормозить, ибо все делается в нем самом. Минус в том, что нужно хорошо знать как сам SQL, так и особенности конкретного типа SQL-сервера. Перенос такой базы с одного типа сервера на другой "как есть" не всегда возможен - придется подкручивать детали, а это может оказаться не просто. А можно всю БЛ реализовать на "клиенте", в какой-нибудь ORM. На сервере лишь таблицы. Без ключей, ограничений, типов данных (все стринги или двоичные) и т.д. Тогда вся "требуха" будет препарироваться в приложениях, точнее, в ORM, подключенных к приложениям. Кстати, можно обойтись вообще без SQL-сервера, данные хранить в папках в виде excel, txt, xml и т.д.) Приведены две крайности, которые в жизни, возможно, и не существуют. А существует лишь их "симбиозы", комбинации. И вот для создания подобных комбинаций требуются и опыт, и знания, и, если угодно, искусство ![]() Большинство новичков не понимают или не знают вышеописанного, и мостят "базы" как блины, сразу ваяя таблицы, которые потом как-то лепят друг к другу, постоянно правя как их структуру, так и количество. Отчего и получают в итоге уродцев. С которыми и маются, бедолаги
0
|
|||
|
9 / 6 / 3
Регистрация: 10.01.2020
Сообщений: 330
|
|||||||||||||||
| 18.02.2021, 18:54 [ТС] | |||||||||||||||
|
Моя модель
Или вы куда-то не туда смотрите. Но суть в том, что если другое приложение в этот момент вставит такую же строку, то у меня будет исключение, которое обработается, и пойдёт работать дальше. А в вашей модели, будет дублирующая запись. Если есть возможность сделать запрет дублирования в СУБД, зачем полагаться только на код? Как по мне, то это костыль. Есть реляционная БД, но мне почему-то ненужно использовать её возможности? Что это такое чудо в [5] и (вроде той, что в [5] и в [3])? Что значит классика? У нас отличие таблицы только в том, что у меня PRIMARY KEY (`StudentId`, `CourseId`), а у вас PRIMARY KEY (`Id`), Какая же это классика, если вы предлагаете проверять кодом дубли и не используете ограничения СУБД? Или о чём вы вообще говорите? Это такой троллинг? Взагали по загалям? p.s. Я не пытаюсь никого обидеть, но не пойму о чём вы конкретно. В соседних ветках, мне писали вещи с которыми я не был согласен, но внятно. Я гуглил, изучал, и делал выводы, в чём-то соглашался, а в чём-то нет. Но здесь я не пойму что вы пытаетесь мне доказать. Мой код грабли с костылем? ОК. Так покажите что конкретно не так? Покажите ваше искусство.
0
|
|||||||||||||||
|
785 / 616 / 273
Регистрация: 04.08.2015
Сообщений: 1,713
|
|
| 19.02.2021, 10:03 | |
|
0
|
|
|
9 / 6 / 3
Регистрация: 10.01.2020
Сообщений: 330
|
|||
| 19.02.2021, 10:31 [ТС] | |||
|
Посмотрите под спойлером "Сущности C# для linq2db" первого сообщения. В таблице `Course` есть `Hours` то есть сколько часов длится курс. (в Сущности C# для linq2db там есть, а в sql пропустил) А в таблице `Student` есть `TotalHours` то есть общее время уже пройденных лекций, по всем курсам. Я думал что в StudCurse `SCHours` попал по невнимательности. Ну тогда есть курс (5214, 'Биология', 25). И этот курс с этим номером длится 25 часов для любого студента. Добавив `SCHours` в таблицу `StudCurse` многие ко многим мы будем дублировать это число для всех студентов. Это же не индивидуальный курс, а для многих студентов, тогда согласно принципам СУБД это значение должно храниться в одном экземпляре. Если вдруг добавится + 2 часа занятий, то нужно будет менять по всей таблице `StudCurse`? А `TotalHours` это значение индивидуально на каждого студента, поэтому оно и в таблице Student.
0
|
|||
|
785 / 616 / 273
Регистрация: 04.08.2015
Сообщений: 1,713
|
|||
| 19.02.2021, 12:45 | |||
|
0
|
|||
|
9 / 6 / 3
Регистрация: 10.01.2020
Сообщений: 330
|
|||
| 19.02.2021, 13:52 [ТС] | |||
|
Это количество часов уже по факту пройденных заданий. Эти данные есть только на сервере. Студент мог записаться на курс, но не ходить, или отходить 10 часов вместо 23 и т.д.
0
|
|||
|
1497 / 1238 / 245
Регистрация: 04.04.2011
Сообщений: 4,363
|
|||||||
| 19.02.2021, 15:03 | |||||||
Это простейший пример, на котором видна связка таблиц через кросс-таблицу. Что же касается решения, то для него слишком мало информации. Прежде всего потому, что нет внятного описания Модели БД в целом. Что за сущности "Курсы" ? Возможно, есть ситуация когда один и тот же предмет читается разное количество часов для разных специальностей (факультетов). Тогда нужна еще одна таблица - таблица предметов. Возможно, потребуется и таблица преподавателей, ведь курсы по предметам читают именно они. Задача описана слишком абстрактно, о каких "решениях" может тут идти речь ? Добавлено через 16 минут Что же касается "посещений" - тут явно не хватает еще 2-х таблиц:
В этом случае кросс-таблица StudCurse вовсе не нужна. Добавлено через 16 минут А вот примерное решение: 1. Сущность "Предметы" (ID, наименование, дисциплина, краткая характеристика и т.д.) 2. Сущность "Кафедра" (ID, наименование, адрес: корпус, комната, телефон, ФИО завкафедрой и т.д.) 3. Сущность "Факультет" (ID, наименование, вид обучения и т.д.) 4. Сущность "Преподаватель" (ID, ФИО, телефон, адрес, ссылка на кафедру и т.д.) 5. Сущность "Группа" (ID, номер, наименование, ссылка на базовую кафедру, ссылка на факультет, ссылка на препода-куратора и т.д.) 6. Сущность "Студент" (ID, ссылка на группу, ФИО, телефон, адрес и т.д.) 7. Сущность "Курс" (ID, ссылка на предмет, ссылка на преподавателя, ссылка на факультет, кол-во часов и т.д.) 8. Сущность "Лекция" (ID, ссылка на курс, ссылка на преподавателя - лекцию может читать не "основной" преподаватель, дата-время, количество часов, аудитория и т.д. 9. Сущность "Посещение" (ID, ссылка на лекцию, ссылка на студента, причина отсутствия и т.д.) В этой модели нет кросс-таблицы за ненадобностью. При этом можно получить любую информацию о посещениях (пропусках, в т.ч. по определенной причине) как по факультету, кафедре, группе, студенту - с одной стороны, так и по предмету (курсу), предметам (курсам), преподавателям - с другой. Добавлено через 12 минут Интерфейс для регистрации посещений/отсутствий предельно прост и ясен: Из расписания (таблица курсов по факультету или общая) выбирается нужная запись и из списка групп выбирается группа (группы). По всему этому строится таблица в памяти, отображаемая через грид. В гриде список студентов с указанием групп, который можно сортировать/фильтровать. В гриде единственная колонка для редактирования, куда вводится только причина отсутствия. Если студент присутствовал, его ячейка в этой колоне остается пустой. Когда все заполнено (точнее, отмечены отсутствующие) жмется кнопка "Сохранить", по которой все записи грида инсертами заливаются в таблицы "Лекция" (одна запись) и "Посещение" (для каждого студента).
0
|
|||||||
| 19.02.2021, 15:03 | |
|
Помогаю со студенческими работами здесь
20
The INSERT statement conflicted with the FOREIGN KEY Конфликт инструкции INSERT с ограничением Foreign Key
Конфликт инструкции INSERT с ограничением FOREIGN KEY Конфликт инструкции INSERT с ограничением FOREIGN KEY Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
|||
|
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога
Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
|
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование
. \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json>
Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом.
# Check if. . .
|
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так:
https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347
Основана на STM32F303RBT6.
На борту пять. . .
|
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
|
|
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу,
и светлой Луне.
В мире
покоя нет
и люди
не могут жить в тишине.
А жить им немного лет.
|
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила»
«Время-Деньги»
«Деньги -Пуля»
|
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога
Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
|
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога
Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
|