Отношение один-к-одному (one-to-one) между таблицами

между двумя таблицами базы данных указывает на то, что для одной строки главной таблицы, обязательно определяется одна связанная строка в зависимой таблице. Это отношение имеет еще один подвид, который называется ноль-или-один-к-одному (zero-or-one-to-one). При этом отношении, в зависимой таблице необязательно указывать связанную строку, т.е. одной строке в главной таблице, может соответствовать ноль или одна строка в зависимой таблице.
При определении отношения один-к-одному в модели данных Entity Framework, вы должны использовать только двустороннюю связь между классами, т.е. нужно указывать навигационное свойство в каждой таблице (если вы используете Fluent API для настройки, следовать этому правилу необязательно). Эти навигационные свойства должны иметь тип ссылки (а не коллекции), чтобы Code-First понял, что используется связь один-к-одному, при этом используемой по умолчанию связью, будет ноль-или-один-к-одному.
Давайте добавим в нашу модель класс профиля покупателя Profile, который свяжем с таблицей Customer:
public class Customer < public int CustomerId < get; set; >public string FirstName < get; set; >public string LastName < get; set; >public string Email < get; set; >public int Age < get; set; >public byte[] Photo < get; set; >public List Orders < get; set; >public Profile Profile < get; set; >> public class Profile < [Key] public int CustomerId < get; set; >public DateTime RegistrationDate < get; set; >public DateTime LastLoginDate < get; set; >public Customer CustomerOf < get; set; >> public class Order < // . эта таблица не изменилась >
В этом примере изначально допущена ошибка. Code-First не сможет определить, какой класс является зависимым в этой ситуации (т.е. для какого класса нужно создать внешний ключ). Если вы запустите приложение с этой моделью, то EF сгенерирует исключение InvalidOperationException, указав, что не может определить основной класс в связке Profile-Customer.
Простым решением этой проблемы является явное указание внешнего ключа в зависимой таблице. При создании отношения один-к-одному Entity Framework требует, чтобы внешний ключ в зависимой таблице являлся и первичным ключом для этой таблицы. В нашем случае в классе Profile определен первичный ключ CustomerId, для которого мы должны указать, что он является и внешним ключом. Как описывалось ранее, это можно сделать указав свойству CustomerId атрибут ForeignKey, с переданным ему именем навигационного свойства:
public class Profile < [Key] [ForeignKey("CustomerOf")] public int CustomerId < get; set; >public DateTime RegistrationDate < get; set; >public DateTime LastLoginDate < get; set; >public Customer CustomerOf < get; set; >>
Если вы теперь запустите приложение, то Entity Framework корректно создаст таблицу Profiles. Как показано на рисунке ниже, ключ CustomerId является как первичным, так и внешним ключом для этой таблицы:

Ранее, при обсуждении использования внешних ключей мы говорили, что атрибут ForeignKey можно применить не только к свойству ключа в модели, но и к навигационному свойству. Для нашей модели такой подход является ошибочным, если вы примените атрибут [ForeignKey(“CustomerId”)] к свойству CustomerOf в классе Profile, Code-First не поймет, в какой таблице нужно будет создать внешний ключ, т.к. и таблица Customer и Profile содержат поле CustomerId. Так что данный способ определения внешних ключей не подходит для нашего сценария.
На следующем рисунке показана диаграмма, на которой можно видеть отношение ноль-или-один-к-одному между таблицами Customers и Profiles:

В контексте нашего примера, отношение ноль-или-один-к-одному означает, что для покупателя не обязательно указывать данные профиля, но при этом для профиля всегда есть один связанный с ним покупатель. В примере ниже показано, как настроить отношение ноль-или-один-к-одному с помощью Fluent API без использования атрибута ForeignKey:
protected override void OnModelCreating(DbModelBuilder modelBuilder) < modelBuilder.Entity() .HasRequired(p => p.CustomerOf) .WithOptional(c => c.Profile); >
Обратите внимание, что здесь не нужно использовать метод HasForeignKey() для явного указания внешнего ключа. Этого кода на самом деле достаточно для Code-First, чтобы показать, что класс Profile является зависимым, а свойство Profile.CustomerId должно являться внешним ключом. Это связано с тем, что при определении отношения one-to-one (или zero-or-one-to-one) первичный ключ в зависимой таблице должен автоматически быть внешним ключом.
Теперь давайте смоделируем явное отношение один-к-одному между нашими таблицами. В контексте нашего примера это означает, что для покупателя всегда должна определяться информация профиля. Одному покупателю соответствует один профиль. В аннотациях данных это можно сделать с помощью атрибута Required, который применяется к навигационному свойству главной таблицы, как показано в примере ниже:
public class Customer < // . [Required] public Profile Profile < get; set; >>
В результате, если мы попытаемся вставить данные нового заказчика, не указав для него профиль, то Entity Framework сгенерирует ошибку. Следует отметить, что при реализации отношения один-к-одному структура базы данных не меняется, изменения касаются только модели, которые уведомляют EF об обоюдной зависимости таблиц Customer и Profile.
Отношение один-к-одному можно создать, используя также Fluent API. Логично было бы предположить, что для этого используется вызов метода HasRequired с последующим вызовом WithRequired. Однако, Fluent API предлагает вместо вызова WithRequired использовать два следующих метода: WithRequiredDependent или WithRequiredPrincipal. Выбор нужного метода зависит от того, к какой таблице он применяется – зависимой (WithRequiredPrincipal укажет ссылку на основную таблицу) или основной (WithRequiredDependent укажет ссылку на зависимую таблицу). Чтобы в этом разобраться, достаточно взглянуть на простой пример:
protected override void OnModelCreating(DbModelBuilder modelBuilder) < modelBuilder.Entity() // Этот метод вернет ссылку на объект конфигурации Customer .HasRequired(p => p.CustomerOf) // Поэтому мы применяем метод WithRequiredDependent, // т.к. Customer является основной таблицей .WithRequiredDependent(c => c.Profile); // Следующая настройка аналогична предыдущей modelBuilder.Entity() .HasRequired(c => c.Profile) .WithRequiredPrincipal(p => p.CustomerOf); >
Здесь важно отметить, что если вы перепутаете в этом примере вызовы этих методов, например:
protected override void OnModelCreating(DbModelBuilder modelBuilder) < modelBuilder.Entity() .HasRequired(p => p.CustomerOf) .WithRequiredPrincipal(c => c.Profile); >
Тогда Entity Framework создаст таблицу Customer как зависимую от Profile. Это выражается в том, что внешний ключ будет установлен в поле Customer.CustomerId, а не в Profile.CustomerId, как это делалось раньше.
В примерах выше мы использовали перегруженные методы WithRequiredDependent() и WithRequiredPrincipal() передавая в параметре ссылку на навигационное свойство. Однако эти методы можно указывать без параметров. Делать это следует только в том случае, если в классах таблиц, к которым они применяются, отсутствуют соответствующие навигационные свойства. Т.е. благодаря вызову этих методов без параметров, мы можем моделировать связь один-к-одному используя одностороннее отношение между классами (когда навигационное свойство указывается только в одном из классов).
Существует еще одна разновидность отношения один-к-одному, которую мы еще не рассмотрели, это отношение ноль-или-один-к-ноль-или-одному (zero-or-one-to-zero-or-one). В контексте нашего примера это отношение говорит о том, что для любого покупателя может существовать ноль или один профиль, и для любого профиля может существовать ноль или один покупатель. В модели магазина такая связь не имеет логического смысла – как может существовать профиль пользователя без пользователя? Однако, в некоторых случаях вам может понадобиться создать эту связь.
Для реализации связи ноль-или-один-к-ноль-или-одному в Fluent API существуют специальные методы WithOptionalDependent() и WithOptionalPrincipal(), смысл которых аналогичен соответствующим методам WithRequired… , но они применяются после вызова метода HasOptional(), как показано в примере ниже:
protected override void OnModelCreating(DbModelBuilder modelBuilder) < modelBuilder.Entity() .HasOptional(p => p.CustomerOf) .WithOptionalDependent() .Map(p => p.MapKey("ProfileKey")); // Аналогичная настройка modelBuilder.Entity() .HasOptional(c => c.Profile) .WithOptionalPrincipal() .Map(c => c.MapKey("CustomerKey")); >
Обратите внимание, что в этом примере мы явно задаем имя для внешних ключей, используя вспомогательный метод Map(). В результате, Entity Framework добавит внешний ключ как в таблицу Customers, так и в таблицу Profiles:

Фактически, отношение ноль-или-один-к-ноль-или-одному идентично двум отношениям ноль-или-один-к-одному между нашими таблицами.
Создание связи «один к одному»

Связи «один к одному» часто используются для получения важных данных, необходимых для ведения бизнеса.
Связь «один-к-одному» — это связь между информацией из двух таблиц, когда каждая запись используется в каждой таблице только один раз. Например, связь типа «один-к-одному» может использоваться между сотрудниками и их служебными автомобилями. Каждый работник указан в таблице «Сотрудники» только один раз, как и каждый автомобиль в таблице «Служебный транспорт».
Связи «один-к-одному» можно использовать, если у вас есть таблица со списком элементов, но конкретные сведения о них зависят от типа. Например, у вас может быть таблица контактов, в которой некоторые сотрудники являются сотрудниками, а другие — субподрядчиками. Для сотрудников нужно знать их номера, расширения и другие ключевые сведения. Для субподрядчиков нужно знать, помимо прочего, название компании, номер телефона и тариф на выставление счета. В этом случае нужно создать три отдельные таблицы — «Контакты», «Сотрудники» и «Субподрядчики», а затем создать связь «один-к-одному» между таблицами «Контакты» и «Сотрудники» и связь «один-к-одному» между таблицами «Контакты» и «Субподрядчики».
Общие сведения о создании связи «один к одному»
Связи «один-к-одному» создаются путем связывания индекса первой таблицы, в качестве которого обычно выступает первичны ключ, с индексом второй таблицы, причем их значения совпадают. Пример:

Часто бывает, что лучший способ создать подобную связь — назначить вторичной таблице функцию поиска значений из первой таблицы. Например, вы можете сделать поле «Код автомобиля» в таблице «Сотрудники» полем подстановки, которое будет искать значение индекса «Код автомобиля» в таблице «Служебный транспорт». Таким образом исключается случайное добавление кода автомобиля, который на самом деле не существует.
Важно: При создании связи «один-к-одному» следует тщательно обдумать, требуется ли включать для нее обеспечение целостности данных.
Целостность данных помогает Access поддерживать порядок данных путем удаления связанных записей. Например, при удалении сотрудника из таблицы «Сотрудники» также удаляются записи о его льготах из таблицы «Льготы». Но в некоторых связях, таких как в этом примере, целостность данных не имеет смысла: если удалить сотрудника, мы не хотим, чтобы автомобиль удалялся из таблицы «Автомобиль компании», так как он по-прежнему будет принадлежать компании и будет назначен другому сотруднику.
Инструкции по созданию связи типа «один к одному»
Вы можете создать связь «один-к-одному», добавив в таблицу поле подстановки. (Инструкции см. в статье Создание таблиц и назначение типов данных.) Например, чтобы указать, какие автомобили назначены определенным сотрудникам, вы можете добавить в таблицу «Сотрудники» поле «Код автомобиля». После этого воспользуйтесь мастером подстановок для создания связи между полями.

- Откройте таблицу.
- В режиме конструктора добавьте новое поле, выберите значение Тип данных, а затем запустите мастер подстановок.
- В мастере по умолчанию выбран поиск значений в другой таблице, поэтому нажмите кнопку Далее.
- Выберите таблицу с ключом (обычно первичным), который вы хотите добавить в первую таблицу, и нажмите кнопку Далее. В рассмотренном примере следует выбрать таблицу «Служебный транспорт».
- Добавьте в список Выбранные поля поле с необходимым ключом. Нажмите кнопку Далее.
- Задайте порядок сортировки и, при необходимости, измените ширину поля.
- В последнем окне установите флажок Включить проверку целостности данных и нажмите кнопку Готово.
Как сделать связь между таблицами один к одному?
Задача искусственная. На практике такая связь почти никогда не используется. Разве что достигнуто ограничение на количество полей (атрибутов).
28 окт 2020 в 11:31
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
Сделайте вот так:
create table a ( id number(5) primary key, name varchar2 (128)) / create table b ( id number(5) not null unique references a (id), name varchar2 (128)) /
Ограничение unique обеспечит связь один-к-одному, а заодно, добавит индекс для внешнего ключа, который не создаётся автоматически.
Отслеживать
ответ дан 28 окт 2020 в 1:40
51.6k 200 200 золотых знаков 61 61 серебряный знак 242 242 бронзовых знака
Pasport И ID_Card это записи в Table
28 окт 2020 в 7:47
@TeonaNadiradze Извините, ожидал информацию по таблице, а не данные. Поправил.
28 окт 2020 в 11:12
- sql
- oracle
-
Важное на Мете
Похожие
Подписаться на ленту
Лента вопроса
Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.
Дизайн сайта / логотип © 2023 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2023.11.15.1019
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.
Типы связей в реляционных базах данных
Примечание:
Во всех статьях текущей категории уроков по SQL используются примеры и задачи, основанные на учебной базе данных.
Приступая к изучению данного материала, рекомендуется ознакомиться с описанием учебной БД.
Практически всегда БД не ограничивается одной таблицей. Сложно представить себе какой-либо бизнес-процесс на предприятии, который мог бы сконцентрироваться только на одном предмете в плане информации.
Рассмотрим пример учебной базы данных. Имеется отдел, который занимается обработкой звонков, поступающих на различные линии. Линии обслуживаются конкретными операторами. Операторы состоят в разных группах под присмотром супервайзеров.
Только из данного краткого описания можно выделить несколько самостоятельных объектов:

- Телефонные линии обслуживания;
- Сотрудники отдела;
- Должности сотрудников;
- Группы, по которым распределены сотрудники;
- Звонки.
Ознакомившись с диаграммой базы данных, можно обратить внимание на то, что некоторая информация из одних таблиц присутствует в других, т.е. между ними имеются связи.
В нашем конкретном случае, все таблицы можно соединить между собой. Чтобы понять, как это правильно сделать, необходимо рассмотреть типы связей.
Логику соединения таблиц в БД важно понять с самого начала изучения SQL, так как наверняка Вы не будете писать запросы только к одной таблице.
Всего существует 3 типа связей:
Примечание:
В данном материале обозначения связей приводятся на примере MS SQL Server. В иных СУБД они могут обозначаться по-разному, но у Вас не должно возникнуть проблем с определением их типа, т.к. они либо очень похожи, либо интуитивно понятны.
Связь «Один к одному»
Связь один к одному образуется, когда ключевой столбец (идентификатор) присутствует в другой таблице, в которой тоже является ключом либо свойствами столбца задана его уникальность (одно и тоже значение не может повторяться в разных строках).
На практике связь «один к одному» наблюдается не часто. Например, она может возникнуть, когда требуется разделить данных одной таблицы на несколько отдельных таблиц с целью безопасности.
В учебной безе данных нет подходящего примера, но гипотетически могла бы существовать необходимость разделения таблицы сотрудников.
Пример:
Представьте, что базой данных пользуются несколько менеджеров и аналитиков, а таблица «Сотрудники» содержит те же столбцы, что и учебная база. Следовательно, доступ к персональным данным может получить любой из упомянутых работников.
Чтобы устранить возможность утечки конфиденциальной информации, принимается решение о переносе информации паспортных данных в отдельную таблицу, доступ к которой предоставляется ограниченному кругу лиц.
Связь «Один ко многим»
В типе связей один ко многим одной записи первой таблицы соответствует несколько записей в другой таблице.
Рассмотрим связь учебной базы данных между должностями и сотрудниками, которая относится к рассматриваемому типу.
Записи должностей в таблице «Должность» уникальны, так как нет смысла повторно создавать имеющуюся запись. Записи в таблице «Сотрудники» также уникальны, но несколько различных сотрудников могут находиться на одинаковой должностной позиции.
Символ ключа на конце связи указывает, что таблица, к которой этой конец прилегает, находится на стороне «один» (связанный столбец является первичным ключом), а символ бесконечности находится на стороне «многие» (такой столбец является внешним ключом).
Связь «Многие ко многим»
Если нескольким записям из одной таблицы соответствует несколько записей из другой таблицы, то такая связь называется «многие ко многим» и организовывается посредством связывающей таблицы.
В нашей базе подобное наблюдается только между таблицами с сотрудниками и линиями.
Из диаграммы видно, что имеются две связи «один ко многим» (один сотрудник может обрабатывать несколько телефонных линий, и одну линию могут обрабатывать несколько сотрудников), но в совокупности они образуют связь «многие ко многим».
Для чего все это нужно?
Связи выполняют более важную роль, чем просто информация размещения данных по таблицам. Прежде всего они требуются разработчикам для поддержания целостности баз данных.
Правильно настроив связи, можно быть уверенным, что ничего не потеряется.
Представьте, что Вы решили удалить одну из групп в таблице учебной базы данных. Если бы связи не было, то для тех сотрудников, которые к ней были определены, остался идентификатор несуществующей группы. Связь не позволит удалить группу, пока она имеется во внешних ключах других таблиц. Для начала следовало определить сотрудников в другие имеющиеся или новые группы, а только затем удалить ненужную запись. Поэтому связи называют еще ограничениями.
- Объединение таблиц – UNION
- Соединение таблиц – операция JOIN и ее виды
- Тест на знание основ SQL
Если материалы office-menu.ru Вам помогли, то поддержите, пожалуйста, проект, чтобы я мог развивать его дальше.