Форум программистов, компьютерный форум, киберфорум
C#: Базы данных
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.61/18: Рейтинг темы: голосов - 18, средняя оценка - 4.61
76 / 54 / 22
Регистрация: 26.02.2017
Сообщений: 206

Внешний ключ на таблицу с составным первичным ключом

28.06.2021, 19:24. Показов 3675. Ответов 10

Студворк — интернет-сервис помощи студентам
Всем доброго дня!
Использую Entity Framework и подход CodeFirst. У меня есть таблица Курсы, в которой первичный ключ является составным и состоит из внешних ключей таблиц предметы и преподаватели:
C#
1
2
3
4
5
6
7
8
9
10
11
    public class Course
    {
        [Key, Column(Order = 1)]
        public int SubjectId { get; set; }
 
        [Key, Column(Order = 2)]
        public int ProfessorId { get; set; }
 
        public virtual Subject Subject { get; set; }
        public virtual Professor Professor { get; set; }
    }
И еще есть таблица "Задания" с отношением к таблице "Курсы" один-ко-многим. Т.е. в одном курсе может быть много заданий. Вопрос в том, как мне указать внешний ключ в Заданиях на Курс?
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
28.06.2021, 19:24
Ответы с готовыми решениями:

Как программно добавить запись в таблицу с автоинкрементным первичным ключом
Собственно вопрос в заголовке, подробности такие: использую C# VS2008 SQL Server подключена с помощью Dataset, с данными работа с помощью...

Вставка новой записи в таблицу с составным ключом Fluent NHibernate
День добрый всем. Имею сущность Person Имею сущность Program У каждого Person может быть несколько Program и у каждой Program...

Добавление данных в таблицы с первичным ключом
Как сделать в vba, чтоб в двух связанных таблицах добавлять данные одним запросом, я раньше делал это с помощью двух запросов через...

10
1497 / 1238 / 245
Регистрация: 04.04.2011
Сообщений: 4,363
28.06.2021, 20:45
Если Вы не хотите использовать UID, то в дочерней таблице нужно повторить оба ключа мастера.
Т.е. в таблице курсов будет мин. три ключа - один собственно ключ задания, два других - ключи курса.
Никаких внешних ссылок тут указать нельзя - так и будет Ваша база не нормализованной, т.е. "хромой"
2
76 / 54 / 22
Регистрация: 26.02.2017
Сообщений: 206
29.06.2021, 00:57  [ТС]
Цитата Сообщение от MsGuns Посмотреть сообщение
Если Вы не хотите использовать UID
MsGuns, спасибо за ответ!!! Дело не в том, что я не хочу что то делать... Дело в том, что я не знаю как сделать правильно. Собственно, вопрос об этом и был - как сделать правильно? Можно немного подробнее насчет UID?
0
1497 / 1238 / 245
Регистрация: 04.04.2011
Сообщений: 4,363
29.06.2021, 02:35
Определяем сущности
I. Справочники:
1. Ученые степени
2. Ученые звания

II. Базовые сущности:
1. Факультеты
- Наименование факультета

2. Кафедры
- Наименование кафедры
- Относится к одному, базовому, факультету (relation)

3. Преподавательский состав
- ФИО
- Ученая степень (relation)
- Ученое звание (relation)
- Относится к одной кафедре (relation)

4. Курсы
- Наименование курса
- Преподаватель (relation)
- Количество часов

5. Задачи
- Наименование задачи
- Вес задачи (чем сложнее, тем вес больше - от 1 до 5)
- Относится к курсу (relation)

6. Варианты ответов на задачи
- Текст ответа
- Флажок правильный/ошибочный
- К какой задачи относится (relation)

Добавлено через 25 минут
SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
-- Справочники
CREATE TABLE Dir_AcademicDegree (
    DAD_Id INT IDENTITY(1,1) PRIMARY KEY,
    DAD_Name VARCHAR(MAX) NOT NULL
)
CREATE TABLE Dir_AcademicRank (
    DAR_Id INT IDENTITY(1,1) PRIMARY KEY,
    DAR_Name VARCHAR(MAX) NOT NULL
)
-- Факультеты
CREATE TABLE Faculty (
    F_Id INT IDENTITY(1,1) PRIMARY KEY,
    F_Name VARCHAR(MAX) NOT NULL
)
-- Кафедры
CREATE TABLE Chairsheep (
    CS_Id INT IDENTITY(1,1) PRIMARY KEY,
    CS_F_Id INT REFERENCES Faculity(F_Id) NULL, -- Кафедра может быть "левая"
    CS_Name VARCHAR(MAX)  NOT NULL
)
-- Преподаватели
CREATE TABLE Lecturer (
    L_Id INT IDENTITY(1,1) PRIMARY KEY,
    L_CS_Id INT REFERENCES Chairsheep(CS_Id) NULL, -- Преподаватель может быть со стороны
    L_DAD_Id INT REFERENCES Dir_AcademicDegree(DAD_Id)  NULL, -- Преподаватель может не иметь ученой степени
    L_DAR_Id INT REFERENCES Dir_AcademicRank(DAD_Id)  NULL, -- Преподаватель может не иметь ученого звания
    L_FIO VARCHAR(MAX)  NOT NULL
)
-- Курсы
CREATE TABLE Curse (
    CU_Id INT IDENTITY(1,1) PRIMARY KEY,
    CU_L_Id INT REFERENCES Lecturer(L_Id) NOT NULL, 
    CU_Name VARCHAR(MAX)  NOT NULL,
    CU_HoursAll INT NULL -- Кол-во часов может быть не определено заранее
)
-- Задачи
CREATE TABLE Quest (
    Q_Id INT IDENTITY(1,1) PRIMARY KEY,
    Q_CU_Id INT REFERENCES Curse(CU_Id) NOT NULL, 
    Q_Name VARCHAR(MAX)  NOT NULL,
    Q_Wieght INT NOT NULL
)
-- Варианты ответов
CREATE TABLE QuestAnswer (
    QA_Id INT IDENTITY(1,1) PRIMARY KEY,
    QA_Q_Id INT REFERENCES Quest(Q_Id) NOT NULL, 
    QA_Correct INT NOT NULL  -- 1 - верный ответ, 0 - ошибочный ответ
)
Добавлено через 7 минут
Цитата Сообщение от Svetlana Saphon Посмотреть сообщение
Можно немного подробнее насчет UID?
Прежде чем переходить к следующему этапу нормализации, требуется применить к нашей таблице одно правило (оно же будет действовать для всех таблиц, которые мы создадим позднее).

У каждой сущности должен быть уникальный идентификатор, т.е. некоторый атрибут, имеющий следующие свойства:

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

Для каждого экземпляра сущности он имеет значение в течение всего срока существования экземпляра в БД, причём это значение не меняется, пока экземпляр существует. Это означает, что данный столбец не может быть пустым; причём он заполняется в момент создания строки, и его значение не изменяется вплоть до удаления строки.

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

Теоретически в качестве идентификатора можно выбрать даже несколько полей таблицы, при этом все вместе эти поля должны удовлетворять перечисленным выше требованиям. Так, вряд ли появятся две разные книги одного автора, одного названия и изданные в один год; поэтому из этих трёх полей можно бы сделать идентификатор. Но работать с ним было бы достаточно неудобно.

На практике проще всего ввести для идентификатора специальное поле (столбец). Обычно его называют ID , от английского identifier – идентификатор. В этом столбце находится целое число, уникальное для каждой строки.

На ER-диаграммах названия идентифицирующих атрибутов обычно подчеркивают или помечают звездочкой. Иногда идентификаторы называют ключевыми полями или ключами.

(Интересно, что библиотекари тоже столкнулись с необходимостью такого идентифицирующего атрибута,. Поэтому каждая библиотечная книга имеет специальный “шифр” или “инфентарный номер”; он обычно подписывается на внутренней стороне обложки.)


http://gimnnik.narod.ru/open-o... p7aa1.html

Добавлено через 5 минут
Поправка :
Я оговорился - UID это немного иное, хотя смысл его такой же, как и у ID - уникально идентифицировать что-то (ПК например) в какой-то среде (например ЛВС)

Вот тут подробнее https://kirillbogatov.github.io/tw/id-and-uid/

Добавлено через 7 минут
В каждом SQL сервере есть свой механизм поддержки Id: в Oracle - это последовательности, в IB/FB - генераторы, в MS SQL/ACCESS - автоинкременты и т.д. Они немного отличаются друг от друга, но похожи в одном - при добавлении новой записи в таблицу ей будет присвоен гарантированно уникальный ключ, который запишется в специально созданное для этого поле.
Все межтабличные связи в правильно спроектированных базах реализованы именно через Id таблиц.
1
76 / 54 / 22
Регистрация: 26.02.2017
Сообщений: 206
29.06.2021, 13:41  [ТС]
MsGuns, спасибо за развернутый ответ, но это все я и так знаю. Мой вопрос был немного не об этом... Давайте я поясню задачу. Смотрите, есть предметы и преподаватели. Т.е. имеем таблицы:
SQL
1
2
3
4
5
6
7
8
9
10
CREATE TABLE [dbo].[Subjects]
(
    [Id] INT IDENTITY(1,1) NOT NULL PRIMARY KEY, 
    [Name] NVARCHAR(50) NOT NULL
)
CREATE TABLE [dbo].[Professors]
(
    [Id] INT IDENTITY(1,1) NOT NULL PRIMARY KEY, 
    [Name] NVARCHAR(50) NOT NULL
)
Но, суть в том, что один и тот же предмет могут вести разные преподаватели. Например, вышку у группы 1 ведет преподаватель Иванов, а ту же вышку, но у группы 2 ведет преподаватель Петров. Соответственно, получается еще одна таблица, в которой первичный ключ будет состоять из внешних ключей на таблицы предметы и преподаватели. Т.е. так:
SQL
1
2
3
4
5
6
7
8
9
10
CREATE TABLE [dbo].[Courses]
(
    [SubjectId] INT NOT NULL , 
    [ProfessorId] INT NOT NULL, 
    [GroupId] INT NOT NULL,
    PRIMARY KEY ([SubjectId], [ProfessorId], [GroupId]), 
    CONSTRAINT [FK_Table_ToGroups] FOREIGN KEY ([GroupId]) REFERENCES [Groups]([Id]),
    CONSTRAINT [FK_Table_ToSubjects] FOREIGN KEY ([SubjectId]) REFERENCES [Subjects]([Id]),
    CONSTRAINT [FK_Table_ToProfessors] FOREIGN KEY ([ProfessorId]) REFERENCES [Professors]([Id])
)
Еще у нас есть таблица "Задания". "Задания" и "Курсы" имеют отношение один-ко-многим. И вопрос в том, как мне в этой таблице "Задания" сделать внешний ключ на таблицу "Курсы"? Мне нужно повторить все столбцы, входящих в первичный ключ или есть другой способ?

Добавлено через 5 минут
Цитата Сообщение от MsGuns Посмотреть сообщение
4. Курсы
- Наименование курса
- Преподаватель (relation)
- Количество часов
5. Задачи
- Наименование задачи
- Вес задачи (чем сложнее, тем вес больше - от 1 до 5)
- Относится к курсу (relation)
Можно, конечно, и так сделать... Но, проблема в том, что "Наименование курса" тут не уникальное значение и вполне можно назвать один и тот же предмет по разному. Тогда получится неразбериха, чего бы не хотелось
0
 Аватар для IamRain
4694 / 2702 / 734
Регистрация: 02.08.2011
Сообщений: 7,231
29.06.2021, 14:59
Цитата Сообщение от Svetlana Saphon Посмотреть сообщение
MsGuns, спасибо за развернутый ответ, но это все я и так знаю.
Не обращайте внимания, этот сударь любит про котов-акробатов рассказывать воду лить. Просто создайте у класса Course свойство CourseId (или Id) и сделайте его первичным ключом, и сконфигурируйте обязательные FK на Subject и на Professor. И проблема с добавлением FK из задания на Course сама собой решится - это тривиальные для EF вещи.
1
76 / 54 / 22
Регистрация: 26.02.2017
Сообщений: 206
29.06.2021, 16:25  [ТС]
Цитата Сообщение от IamRain Посмотреть сообщение
Просто создайте у класса Course свойство CourseId (или Id) и сделайте его первичным ключом, и сконфигурируйте обязательные FK на Subject и на Professor.
Вы имеете в виду не включать SubjectId и ProfessorId в первичный ключ, а просто cделать их уникальными?
0
 Аватар для IamRain
4694 / 2702 / 734
Регистрация: 02.08.2011
Сообщений: 7,231
29.06.2021, 16:46
Не включать в первичный ключ, но про уникальность я ничего не говорил. Может ли один и тот же преподаватель вести один и тот же предмет у двух разных курсов? - Думаю, может. Ну тут вы проектировщик, поэтому решать вам.

Добавлено через 6 минут
Может быть так, что есть два разных курса проводимые в разные годы, одним и тем же преподавателем, по одному и тому же предмету, но с совершенно различными планами обучения. На ютубе гляньте курсы Стэнфорда - твм появляется код курса. Остальные атрибуты могут вполне совпадать.
1
1497 / 1238 / 245
Регистрация: 04.04.2011
Сообщений: 4,363
29.06.2021, 16:53
Цитата Сообщение от Svetlana Saphon Посмотреть сообщение
Еще у нас есть таблица "Задания". "Задания" и "Курсы" имеют отношение один-ко-многим. И вопрос в том, как мне в этой таблице "Задания" сделать внешний ключ на таблицу "Курсы"? Мне нужно повторить все столбцы, входящих в первичный ключ или есть другой способ?
В [4] все подробно написано.
Цитата Сообщение от Svetlana Saphon Посмотреть сообщение
Но, проблема в том, что "Наименование курса" тут не уникальное значение и вполне можно назвать один и тот же предмет по разному. Тогда получится неразбериха, чего бы не хотелось
Наименования и не должны быть уникальными, но называние одного и того же курса разными наименованиями действительно может привести к неразберихе. И никакими бизнес-правилами Вы это не поборите.

Добавлено через 1 минуту
В [4] подробно описан пример правильного проектирования БД, но Вы его либо не прочитали ибо
Цитата Сообщение от Svetlana Saphon Посмотреть сообщение
но это все я и так знаю
, либо не поняли.

Добавлено через 3 минуты

Не по теме:

IamRain, Реагирую в первый и последний раз на подобные высказывания.
Каждый плавает как может и хочет. Если есть по-существу, будьте любезны,- с интересом почитаю. А если личная неприязнь, то, извините,- "ф топку"

1
 Аватар для IamRain
4694 / 2702 / 734
Регистрация: 02.08.2011
Сообщений: 7,231
29.06.2021, 17:01
Svetlana Saphon, надо вернуться к определенияю курса.
Ятп курс - это некая программа обучения, по некоторому предмету, имеющая некоторый код (кодовое имя), дату создания, длительность курса (в любых единицах) и не привязанная к преподавателю. А вот CourseSession (на один курс - много CourseSession) - это уже можно привязывать лектора и практикантов.

Не по теме:

MsGuns, ничего личного, просто в силу своей привычки, еще со школьной скамьи, я люблю читать.
Вижу текст (пусть даже портянка) на интересную тематику - читаю. В nn-ый раз читаю ваши посты - трээш на 80%.
Можно сказать, что это в какой-то мере, пусть очень малой, кража времени.

1
76 / 54 / 22
Регистрация: 26.02.2017
Сообщений: 206
29.06.2021, 17:33  [ТС]
MsGuns и IamRain, огромное спасибо за помощь!
Цитата Сообщение от IamRain Посмотреть сообщение
Ятп курс - это некая программа обучения, по некоторому предмету, имеющая некоторый код (кодовое имя), дату создания, длительность курса (в любых единицах) и не привязанная к преподавателю.
В моем случае курс - это сущность объединяющая предмет, преподавателя и группу. На реальность данная модель не претендует. Все очень упрощенно.
Цитата Сообщение от IamRain Посмотреть сообщение
Может ли один и тот же преподаватель вести один и тот же предмет у двух разных курсов? - Думаю, может.
Ну в реале то да, не спорю. Но мне так глубоко копать не нужно) Мне достаточно упрощенной модели. Хотя, если честно, Вы заставили меня задуматься над этим
Цитата Сообщение от MsGuns Посмотреть сообщение
но Вы его либо не прочитали
Прочитала)))
Цитата Сообщение от MsGuns Посмотреть сообщение
либо не поняли
Я поняла, что и как Вы реализовали, но это не совсем то, что мне было нужно. По крайней мере, не так как у меня задумано)))
Цитата Сообщение от MsGuns Посмотреть сообщение
Наименования и не должны быть уникальными, но называние одного и того же курса разными наименованиями действительно может привести к неразберихе. И никакими бизнес-правилами Вы это не поборите.
Вот для этого я и хочу вынести названия предметов в отдельную таблицу. Чтобы название предмета вводилось 1 раз, а не при создании каждого курса. Да, разумеется, никто не мешает внести в таблицу несколько разных вариантов написания одного и того же предмета, но это уже другая история)))

По итогу, благодаря подсказке IamRain было реализовано так:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    [Index(nameof(SubjectId), nameof(ProfessorId), nameof(GroupId), IsUnique = true)]
    public class Course
    {
        public Course()
        {
            CourseWorks = new HashSet<CourseWork>();
        }
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
 
        public int SubjectId { get; set; }
        public int ProfessorId { get; set; }
        public int GroupId { get; set; }
 
        public virtual Subject Subject { get; set; }
        public virtual Professor Professor { get; set; }
        public virtual Group Group { get; set; }
 
        public virtual ICollection<CourseWork> CourseWorks { get; set; }
    }
Теперь все отлично работает, как мне и нужно.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
29.06.2021, 17:33
Помогаю со студенческими работами здесь

Удаление данных из таблицы с первичным ключом
Удаление данных из таблицы с первичным ключом невозможно, так как её данные содержатся в другой таблице. раньше я работал в IBExpert, там...

Создание строки с первичным ключом в MySQL
Всем привет, недавно задался вопросом, как создать строку с первичным ключом в таблице. Можно как и командами, но желательно без...

Почему логин не может быть первичным ключом
Когда я показывал преподавателю схему своей БД, он сказал, что логин не может быть первичным ключом. На вопрос &quot;почему&quot; - он...

пример создания и работы с первичным ключом paradox
Нужен пример работы с primary key в paradox (создание и работа с первичном ключом в отдельном файле *.PX) Использую MS ADO 2.8 в MS...

Как узнать, является ли первичным ключом поле в БД
Как можно узнать, имея на руках только имя таблицы, имя поля (или имена полей), которые являются первичными ключами? БД - Microsoft...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
11
Ответ Создать тему
Новые блоги и статьи
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. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru