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

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

28.06.2021, 19:24. Показов 3631. Ответов 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
4693 / 2701 / 734
Регистрация: 02.08.2011
Сообщений: 7,224
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
4693 / 2701 / 734
Регистрация: 02.08.2011
Сообщений: 7,224
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
4693 / 2701 / 734
Регистрация: 02.08.2011
Сообщений: 7,224
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
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru