что такое связывание данных

Динамическое связывание данных в HTML и JS

Про MVVM:
MVVM (Model-View-ViewModel) — это улучшеная форма MVP, при чем грань между ними так тонка, что иногда думаешь: «О, небо! За что ты так со мной?»

Сейчас объясню что я имею ввиду.

что такое связывание данных. Смотреть фото что такое связывание данных. Смотреть картинку что такое связывание данных. Картинка про что такое связывание данных. Фото что такое связывание данных

Если отбросить формальности, то так оно и есть. Поэтому я и сказал, что грань между MVP и MVVM очень тонка.

Глобально, разница лишь в том, что MVVM реализует более гибкий слушатель событий от View.
При чем реализует таким образом, что становится доступным так называемое декларативное динамическое связывание данных.

Про динамическое связывание данных:
Это такой механизм, при котором, изменив значение модели с любой стороны(со стороны View или Model), это изменение моментально вступит в силу. То есть, изменив значение в Model (в MVVM — ViewModel частично берет на себя функцию модели), оно сразу отобразится во View и наоборот.

Вы можете спросить: «Если в MVP есть двусторонняя связь между View и Presenter, то почему мы не можем реализовать динамическое связывание данных на MVP?».

Ответ очень прост — можем!
По сути, MVP уже подразумевает динамическое связывание данных в той или иной степени.
И, если MVP это чисто императивный подход к связыванию данных, то MVVM — декларативный.

Вот и вся разница.
Но суть у них одна и та же!

Про реализацию:
Теперь рассмотрим вопросы, связанные с реализаций динамического связывания данных.
Начнем с того, что, на текущий момент, браузер не способен динамически отслеживать изменение значений в переменных.
Конечно, есть такая штука как Object.observe(), но эта вещь, пока еще, не является частью стандарта.
Поэтому исходим из того, что

браузер не способен динамически отслеживать изменение значений в переменных

Соответсвенно, необходимо как-то понимать: когда нужно произвести синхронизацию между Model и View.
В современных фреймворках, типа Angular или Knockout, к этому вопросу подходят очень просто: вешают слушатели на разные события от элемента, которому необходимо динамическое связывание данных.
Например, для text input вешается слушатель на событие keyup.
Для button — click
И т.д.

Внутри обработчика происходит чтение новых данных и затем запускается механизм синхронизации оных с Model.

Вот, собственно, и вся история.

И, как обещал, ссылка на Gist, в котором реализовано простейшее динамическое связывание данных.

Источник

Продукты и технологии:

В статье рассматриваются:

Недостаток в реализации связывания с данными всегда заключался в необходимости использовать магические строки и стереотипный код, требуемые для передачи изменений в свойства и для связывания UI-элементов с ними. За прошедшие годы появились разнообразные инструментальные наборы и методы, облегчающие связывание с данными, и цель моей статьи — еще больше упростить этот процесс.

Сначала я рассмотрю основы реализации связывания с данными, а также распространенные методы, которые упрощают это (если вы уже знакомы с предметом, то можете спокойно пропустить эти разделы). Далее я разработаю метод, который вы, возможно, еще не рассматривали («третий путь»), и представлю решения для устранения трудностей, возникающих при разработке приложений на основе MVVM. Вы можете получить конечную версию созданной мной инфраструктуры в пакете сопутствующего кода или добавить NuGet-пакет SolSoft.DataBinding в свой проект.

Основы: INotifyPropertyChanged

Реализация INotifyPropertyChanged — предпочтительный способ, обеспечивающий связывание объекта с UI. Интерфейс достаточно прост и содержит всего один член: событие PropertyChanged. Объект должен генерировать это событие при изменении связанного свойства, чтобы уведомить представление о том, что оно должно обновить значение этого свойства на презентационном уровне.

Интерфейс прост, но его реализация — нет. Генерация события вручную с помощью «зашитых» в код текстовых имен свойств — это решение, которое плохо масштабируется и не годится для рефакторинга: вам придется поддерживать синхронизацию текстового имени с именем свойства в коде. Таким подходом вы не расположите к себе своих последователей. Вот пример:

Есть несколько методов, разработанных людьми в ответ на подобную ситуацию и позволяющих сохранять душевное равновесие (см., к примеру, вопрос на форуме Stack Overflow по ссылке bit.ly/24ZQ7CY); большинство этих методов относится к одному из двух типов.

Распространенный метод 1: базовый класс

Один из методов — применение базового класса для повторного использования хотя бы части стереотипной логики. Это также позволяет получать имя свойства программными способами, а не «зашивать» его в код.

Таким образом, переименование UnreadItemCount также приведет к переименованию выражения-ссылки, и код будет по-прежнему работать. Сигнатура RaiseNotifyPropertyChanged была бы следующей:

Получить имя свойства из memberExpression можно разными методами. В блоге MSDN по C# (bit.ly/25baMHM) дан простой пример:

StackOverflow предлагает более детальный листинг (bit.ly/23Xczu2). В любом случае у этого метода есть недостаток: получение имени выражения требует применения отражения, а этот механизм работает медленно. Негативные последствия для производительности могут быть весьма значительными в зависимости от того, сколько уведомлений об изменении свойств вы поддерживаете.

Этот атрибут сообщает компилятору записать имя вызвавшего (UnreadItemCount) как значение необязательного параметра propertyName.

Однако в любом методе, где применяется базовый класс, есть общая проблема: ваш базовый класс «сгорает». Если вам нужно, чтобы ваша модель представления расширяла другой класс, вам не повезло. Кроме того, ничего не делается для обработки «зависимых» свойств (например, свойство FullName объединяет свойства FirstName и LastName, а любое изменение FirstName или LastName должно инициировать изменение и в FullName).

Распространенный метод 2: аспектно-ориентированное программирование

Аспектно-ориентированное программирование (aspect-oriented programming, AOP) — это метод, который в основном обеспечивает постобработку вашего скомпилированного кода (либо в период выполнения, либо сразу после компиляции), чтобы добавить определенные поведения (известные как аспекты). Обычно цель состоит в том, чтобы заменить повторяющийся стереотипный код вроде ведения журналов или обработки исключений (так называемой сквозной функциональности [cross-cutting concerns]). Не удивительно, что реализация INotifyPropertyChanged является хорошим кандидатом для применения AOP.

Для этого подхода доступно несколько инфраструктур. Одна из них — PostSharp (bit.ly/1Xmq4n2). Я был приятно удивлен, узнав, что она должным образом обрабатывает зависимые свойства (например, ранее описанное свойство FullName). Похожей функциональностью обладает инфраструктура Fody с открытым исходным кодом (bit.ly/1wXR2VA).

Генерацией событий вручную с помощью «зашитых» в код текстовых имен свойств вы не расположите к себе своих последователей.

Это привлекательный подход; его недостатки могут оказаться несущественными. Некоторые реализации перехватывают поведение в период выполнения, что влечет за собой некоторые издержки для производительности. Инфраструктуры, выполняющие обработку сразу после компиляции, напротив, не должны вводить никаких издержек в период выполнения, но могут потребовать какой-либо специфической установки или настройки. В настоящее время PostSharp предлагается как расширение Visual Studio. Его бесплатная редакция Express ограничивает использование аспекта INotifyPropertyChanged десятью классами, так что скорее всего вам придется раскошелиться. С другой стороны, Fody является бесплатным NuGet-пакетом, что делает эту инфраструктуру превосходным выбором. Так или иначе, учитывайте, что в любой инфраструктуре AOP код, который вы пишете, — это не совсем тот же код, который вы будете выполнять и отлаживать.

Третий путь

Альтернативный способ — использование объектно-ориентированного проектирования: пусть свойства сами отвечают за генерацию событий! Это не особенно революционная идея, но и не та, которую я встречал бы вне своих проектов. В самой базовой форме она может быть выражена таким образом:

Идея в том, что вы предоставляете свойство с его именем и ссылкой на его владельца и позволяете ему выполнять всю работу по генерации события PropertyChanged — примерно так:

Проблема в том, что на самом деле это не будет работать: я не могу сгенерировать событие из другого класса таким способом. Мне нужен некий контракт с классом-владельцем, который позволил бы мне генерировать его событие PropertyChanged: это как раз подходит для интерфейса, поэтому я создам такой интерфейс:

После этого я могу реализовать NotifyProperty.SetValue:

Реализация IRaisePropertyChanged Требование к владельцу свойства реализовать интерфейс означает, что в каждом классе модели представления понадобится некоторый стереотипный код, как показано на рис. 1. Первая часть обязательна для любого класса, который должен реализовать INotifyPropertyChanged, а вторая является специфичной для нового IRaisePropertyChanged. Заметьте: поскольку метод RaisePropertyChanged не предназначен для универсального использования, я предпочитаю реализовать его в явном виде.

Рис. 1. Код, необходимый для реализации IRaisePropertyChanged

Я мог бы поместить этот стереотипный код в базовый класс и расширять его, что вроде бы возвращает меня к обсуждению в начале статьи. В конце концов, если я применяю CallerMemberName к методу RaisePropertyChanged, то фактически заново изобретаю первый метод. Так в чем же смысл? В обоих случаях я мог бы просто скопировать стереотипный код в другие классы, если их нельзя унаследовать от базового.

Однако в любом методе, где применяется базовый класс, есть общая проблема: ваш базовый класс «сгорает».

Одно ключевое отличие от более раннего метода на основе базового класса состоит в том, что в этом случае в стереотипном коде нет реальной логики; вся логика инкапсулирована в класс NotifyProperty. Проверка на изменение значения свойства до генерации события — это весьма простая логика, тем не менее ее лучше не дублировать. Подумайте, что произошло бы, если бы вы захотели использовать другой IEqualityComparer для выполнения проверки. В этой модели вам понадобилось бы изменить лишь класс NotifyProperty. Даже если у вас есть несколько классов с одинаковым стереотипным IRaisePropertyChanged, каждая реализация могла бы выиграть от изменений только в NotifyProperty — без модификации самого кода. Независимо от того, какие изменения в поведение вы хотите внести, изменение кода IRaisePropertyChanged крайне маловероятно.

Соединяем все воедино Теперь у меня есть интерфейс, который должен быть реализован в модели представления, и класс NotifyProperty, используемый для связываемых с данными свойств. Последний шаг — конструирование NotifyProperty; для этой цели по-прежнему нужно как-то передавать имя свойства. Если вам повезло использовать C# 6, это легко делается оператором nameof. Если нет, вместо него можно создать NotifyProperty с помощью выражений (expressions), например применив метод расширения (к сожалению, CallerMemberName на этот раз не поможет):

При таком подходе у вас по-прежнему будут издержки, связанные с отражением, но только при создании объекта, а не при каждом изменении свойства. Если такой вариант все равно дает слишком большие издержки (вы создаете много объектов), всегда можно кешировать вызов GetName и хранить его как статическое значение только для чтения в классе модели представления. Так или иначе, на рис. 2 показан пример простой модели представления.

Рис. 2. Базовый ViewModel с NotifyProperty

Связывание и переименование Хотя я говорю об именах, неплохо бы обсудить и другую проблему связывания с данными. Надежная генерация события PropertyChanged без «зашитой» в код строки — это лишь одна половинка в поддержке рефакторинга; вторая половинка — само связывание с данными. Если вы переименуете какое-либо свойство, используемое для связывания в XAML, успех отнюдь не гарантирован (см., скажем, bit.ly/1WCWE5m).

Альтернатива — кодирование привязок данных вручную в файле отделенного кода. Например:

Немного странно, что null-объект присутствует исключительно для использования функциональности выражений, но это работает (он не нужен, если у вас есть доступ к nameof).

Я нахожу этот метод ценным, но хорошо понимаю его недостатки. Плюсом является то, что, если я переименую свойство UserName, то могу быть спокоен: рефакторинг будет работать. Еще одно серьезное преимущество — команда Find All References работает ожидаемым образом. Минус в том, что он может оказаться не столь простым и естественным, как при связывания в XAML, и не даст мне сохранить независимость UI. Например, я просто не смогу изменить внешний вид инструмента Blend без модификации кода. Кроме того, этот метод не работает с шаблонами данных; вы можете поместить такой шаблон в пользовательский элемент управления, но это потребует больше усилий.

Надежная генерация события PropertyChanged без «зашитой» в код строки — это лишь одна половинка в поддержке рефакторинга; вторая половинка — само связывание с данными.

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

«Производные» свойства

Ранее я описывал сценарий, где особенно затруднительно генерировать событие PropertyChanged, а именно для свойств, значения которых зависят от других свойств. Я упомянул простой пример со свойством FullName, зависимым от свойств FirstName и LastName. Моя цель в реализации для этого сценария — принимать эти базовые объекты NotifyProperty (FirstName и LastName), а также функцию для вычисления производного от них значения (скажем, FirstName.Value + » » + LastName.Value) и на основе этого создавать объект свойства, который будет автоматически обрабатывать за меня все остальное. Для этого нужно внести в мой исходный NotifyProperty несколько изменений.

Создание класса DerivedNotifyProperty тоже кажется простым, пока вы не начнете пытаться свести воедино все части. Основная идея заключалась в том, чтобы принимать нижележащие свойства и функцию для расчета некоего нового значения на их основе, но тут моментально возникает проблема из-за обобщений. Для приема нескольких разных типов свойств никакого практичного способа нет:

Я могу обойти первую половину проблемы (принимая несколько обобщенных типов) с помощью статических методов Create:

Но производному свойству все равно нужно прослушивать событие ValueChanged в каждом базовом свойстве. Решение этой задачи требует двух этапов. Во-первых, я извлеку событие ValueChanged в отдельный интерфейс:

Функция newDerivedValueFunction — это просто Func без параметров; теперь DerivedNotifyProperty не требуется знание нижележащих типов свойств, поэтому я могу спокойно создать его экземпляр из нескольких свойств разных типов.

Ничто не заставляет вас использовать этот метод только в контексте модели представления UI.

На рис. 3 показан сокращенный листинг класса DerivedNotifyProperty. Заметьте, что этот класс принимает произвольное количество свойств, которые нужно прослушивать; хотя здесь приведен метод Create только для двух нижележащих свойств, я создаю дополнительные перегрузки, принимающие одно, три и более нижележащих свойств.

Рис. 3. Базовая реализация DerivedNotifyProperty

Обратите внимание на то, что нижележащие свойства могут принадлежать разным владельцам. Например, у вас есть модель представления Address со свойством IsAddressValid. Кроме того, вы располагаете моделью представления Order, которая содержит две модели представления Address — для адресов выставления счета и поставки. Было бы резонно создать свойство IsOrderValid в родительской модели представления Order, которое объединяет свойства IsAddressValid дочерних моделей представлений Address, чтобы вы могли передавать заказ, только если правильны оба адреса. Для этого модель представления Address предоставляла бы как bool IsAddressValid < get; >, так и IProperty IsAddressValidProperty < get; >, чтобы модель представления Order могла создать DerivedNotifyProperty, который ссылается на дочерние объекты IsAddressValidProperty.

Полезность DerivedNotifyProperty

Пример с FullName, который я привел для производного свойства, довольно надуманный, но я хочу обсудить некоторые реальные случаи применения и увязать их с принципами проектирования. Я лишь слегка коснулся этой темы в одном из примеров: IsValid. В частности, это весьма простой и эффективный способ отключить кнопку Save на форме. Заметьте: ничто не заставляет вас использовать этот метод только в контексте модели представления UI. Вы можете применять его и для проверки бизнес-объектов; они просто должны реализовать IRaisePropertyChanged.

Вторая ситуация, где производные свойства крайне полезны, — сценарии с углублением (drill down scenarios). В качестве простого примера рассмотрим поле с раскрывающимся списком для выбора страны, где указание конкретной страны вызывает заполнение списка городов. Вы можете превратить SelectedCountry в NotifyProperty и при наличии метода GetCitiesForCountry создавать AvailableCities как DerivedNotifyProperty, который будет автоматически синхронизироваться при смене выбранной страны.

Третья область, где я использовал объекты NotifyProperty, — указание того, занят ли объект. Пока объект считается занятым, определенные UI-функции должны оставаться отключенными и, возможно, пользователь должен видеть индикатор прогресса. Этот сценарий кажется обманчиво простым, но на самом деле его реализация потребует учета уймы тонкостей.

Первая часть — это отслеживание того, занят ли объект; в простом случае это можно сделать с помощью Boolean NotifyProperty. Однако, зачастую случается так, что объект может быть занят по одной из нескольких причин: допустим, я загружаю несколько областей данных — возможно, параллельно. Общее состояние занятости должно зависеть от того, продолжается ли все еще загрузка любого из этих элементов. Вроде бы кажется, что это задача для производных свойств, но тогда реализация получилась бы весьма громоздкой (если она вообще была бы возможной): мне понадобилось бы свойство для каждой возможной операции, чтобы отслеживать, продолжается ли ее выполнение. Вместо этого я хочу сделать для каждой операции нечто вроде следующего, используя одно свойство IsBusy:

Для поддержки этого я создаю класс IsBusyNotifyProperty, который расширяет NotifyProperty в нем храню «счетчик занятости» («busy count»). Я переопределяю SetValue так, чтобы SetValue(true) увеличивал этот счетчик, а SetValue(false) уменьшал. Когда счетчик изменяет значение с 0 на 1, только тогда я вызываю base.SetValue(true), а когда он изменяет значение с 1 на 0 — base.SetValue(false). Тем самым запуск нескольких операций приводит к тому, что IsBusy становится true только раз, а впоследствии он снова получает значение false, лишь когда все операции завершены. Эту реализацию можно посмотреть в сопутствующем исходном коде.

На этом часть, связанную с «занятостью», считайте законченной: состояние «занят» можно связать с видимостью индикатора прогресса. Однако для отключения UI мне нужно противоположное. Когда состояние «занят» — true, состояние «UI включен» должно быть false.

В XAML есть концепция IValueConverter, который преобразует значение в экранное представление или наоборот. Вездесущий пример — BooleanToVisibilityConverter; в XAML свойство Visibility элемента описывается не значением типа Boolean, а перечислимым значением. То есть нельзя связать видимость элемента непосредственно с булевым свойством (вроде IsBusy); вы должны связать значение и попутно использовать конвертер. Например:

Я упомянул, что состояние «UI включен» противоположно состоянию «занят»; может возникнуть соблазн создать конвертер значения для инверсии булева свойства и использовать его для выполнения работы:

В самом деле, до того как я создал класс DerivedNotifyProperty, это был самый простой способ. Он был довольно утомителен в создании отдельного свойства, его подключении для получения обращенного значения IsBusy и генерации соответствующего события PropertyChanged. Но теперь это тривиально, и без этого барьера (т. е. лени) я лучше понимаю, где имеет смысл применять IValueConverter.

В конечном счете представление — где бы оно ни было реализовано (в WPF, Windows Forms или, например, как консольное приложения) — должно быть визуализацией (или проекцией) того, что происходит в нижележащем приложении, и не нести никакой ответственности за определение механизма и бизнес-правил выполняемых операций. В данном случае тот факт, что IsBusy и IsEnabled оказались столь тесно связаны друг с другом, является лишь особенностью этой реализации; вовсе не обязательно, чтобы отключение UI было связано именно с тем, что приложение занято.

В данных условиях я рассматриваю это как серую область и не стану спорить с вами, если вы захотите использовать конвертер значений для реализации этого. Однако я могу привести гораздо более веские аргументы, добавив в пример другую часть. Давайте притворимся, что при потере сети приложение тоже должно отключать UI (и показывать панель с описанием проблемы). Это создает три ситуации. Если приложение занято, я должен отключить UI (и показать панель прогресса). Если приложение теряет доступ к сети, я тоже должен отключить UI (и показать панель «соединение потеряно»). Третья ситуация — приложение подключено к сети и не занято, а значит, готово к приему ввода.

В конечном счете представление должно быть визуализацией того, что происходит в нижележащем приложении.

Попытка реализации при таких условиях без свойства IsEnabled окажется в лучшем случае неуклюжей; вы могли бы задействовать MultiBinding, но это все равно громоздко и поддерживается не во всех средах. В итоге все это обычно указывает на то, что есть способ лучше, и мы уже знаем, что он есть: эту логику предпочтительно обрабатывать в модели представления. Теперь становится тривиальным предоставить два объекта NotifyProperty, IsBusy и IsDisconnected, а затем создать DerivedNotifyProperty, IsEnabled, которое содержит true, только если оба свойства (IsBusy и IsDisconnected) равны false.

Если бы вы пошли по пути IValueConverter и связывания состояния Enabled для UI непосредственно с IsBusy (с конвертером для инверсии его значения), то теперь вам понадобилось бы проделать немало работы. Если бы вместо этого вы предоставили отдельное производное свойство IsEnabled, добавление этих новых битов логики потребовало бы гораздо меньше усилий, и саму привязку IsEnabled даже не пришлось бы изменять. Это добрый знак, указывающий на то, что вы идете по правильному пути.

Заключение

Проектирование этой инфраструктуры было не столь легкой задачей, но в награду за все усилия я теперь могу реализовать уведомления об изменении свойств без повторяющего стереотипного кода, без магических строк и с поддержкой рефакторинга. Мои модели представлений не требуют логики из конкретного базового класса. Я могу создавать производные свойства, которые тоже генерируют подходящие уведомления об изменениях, не прилагая каких-то особых дополнительных усилий. Наконец, этот код работает. И всего этого я добился благодаря разработке сравнительно простой инфраструктуры с объектно-ориентированным дизайном. Надеюсь, что вы сочтете ее полезной в своих проектах.

Выражаю благодарность за рецензирование статьи экспертам Фрэнсису Чэнгу (Francis Cheung) из Microsoft и Чарльзу Малму (Charles Malm) из Zebra Technologies.

Источник

Связи между таблицами базы данных

1. Введение

Связи — это довольна важная тема, которую следует понимать при проектировании баз данных. По своему личному опыту скажу, что осознав связи, мне намного легче далось понимание нормализации базы данных.

1.1. Для кого эта статья?

Эта статья будет полезна тем, кто хочет разобраться со связями между таблицами базы данных. В ней я постарался рассказать на понятном языке, что это такое. Для лучшего понимания темы, я чередую теоретический материал с практическими примерами, представленными в виде диаграммы и запроса, создающего нужные нам таблицы. Я использую СУБД Microsoft SQL Server и запросы пишу на T-SQL. Написанный мною код должен работать и на других СУБД, поскольку запросы являются универсальными и не используют специфических конструкций языка T-SQL.

1.2. Как вы можете применить эти знания?

2. Благодарности

Учтены были советы и критика авторов jobgemws, unfilled, firnind, Hamaruba.
Спасибо!

3.1. Как организовываются связи?

Связи создаются с помощью внешних ключей (foreign key).
Внешний ключ — это атрибут или набор атрибутов, которые ссылаются на primary key или unique другой таблицы. Другими словами, это что-то вроде указателя на строку другой таблицы.

3.2. Виды связей

4. Многие ко многим

Представим, что нам нужно написать БД, которая будет хранить работником IT-компании. При этом существует некий стандартный набор должностей. При этом:

4.1. Как построить такие таблицы?

Слева указаны работники (их id), справа — должности (их id). Работники и должности на этой таблице указываются с помощью id’шников.

На эту таблицу можно посмотреть с двух сторон:

4.2. Реализация

что такое связывание данных. Смотреть фото что такое связывание данных. Смотреть картинку что такое связывание данных. Картинка про что такое связывание данных. Фото что такое связывание данных

С помощью ограничения foreign key мы можем ссылаться на primary key или unique другой таблицы. В этом примере мы

4.3. Вывод

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

5. Один ко многим

Эта самая распространенная связь между базами данных. Мы рассматриваем ее после связи многие ко многим для сравнения.

Предположим, нам нужно реализовать некую БД, которая ведет учет данных о пользователях. У пользователя есть: имя, фамилия, возраст, номера телефонов. При этом у каждого пользователя может быть от одного и больше номеров телефонов (многие номера телефонов).

В этом случае мы наблюдаем следующее: пользователь может иметь многие номера телефонов, но нельзя сказать, что номеру телефона принадлежит определенный пользователь.

Другими словами, телефон принадлежит только одному пользователю. А пользователю могут принадлежать 1 и более телефонов (многие).

Как мы видим, это отношение один ко многим.

5.1. Как построить такие таблицы?

PhoneIdPersonIdPhoneNumber
1511 091-10
2519 124-66
31721 972-02

Данная таблица представляет три номера телефона. При этом номера телефона с id 1 и 2 принадлежат пользователю с id 5. А вот номер с id 3 принадлежит пользователю с id 17.
Заметка. Если бы у таблицы «Phones» было бы больше атрибутов, то мы смело бы их добавляли в эту таблицу.

5.2. Почему мы не делаем тут таблицу-посредника?

Таблица-посредник нужна только в том случае, если мы имеем связь многие-ко-многим. По той простой причине, что мы можем рассматривать ее с двух сторон. Как, например, таблицу EmployeesPositions ранее:

5.3. Реализация

что такое связывание данных. Смотреть фото что такое связывание данных. Смотреть картинку что такое связывание данных. Картинка про что такое связывание данных. Фото что такое связывание данных

6. Один к одному

Представим, что на работе вам дали задание написать БД для учета всех работников для HR. Начальник уверял, что компании нужно знать только об имени, возрасте и телефоне работника. Вы разработали такую БД и поместили в нее всю 1000 работников компании. И тут начальник говорит, что им зачем-то нужно знать о том, является ли работник инвалидом или нет. Наиболее простое, что приходит в голову — это добавить новый столбец типа bool в вашу таблицу. Но это слишком долго вписывать 1000 значений и ведь true вы будете вписывать намного реже, чем false (2% будут true, например).

Более простым решением будет создать новую таблицу, назовем ее «DisabledEmployee». Она будет выглядеть так:

Но это еще не связь один к одному. Дело в том, что в такую таблицу работник может быть вписан более одного раза, соответственно, мы получили отношение один ко многим: работник может быть несколько раз инвалидом. Нужно сделать так, чтобы работник мог быть вписан в таблицу только один раз, соответственно, мог быть инвалидом только один раз. Для этого нам нужно указать, что столбец EmployeeId может хранить только уникальные значения. Нам нужно просто наложить на столбец EmloyeeId ограничение unique. Это ограничение сообщает, что атрибут может принимать только уникальные значения.

Выполнив это мы получили связь один к одному.

Заметка. Обратите внимание на то, что мы могли также наложить на атрибут EmloyeeId ограничение primary key. Оно отличается от ограничения unique лишь тем, что не может принимать значения null.

6.1. Вывод

Можно сказать, что отношение один к одному — это разделение одной и той же таблицы на две.

6.2. Реализация

что такое связывание данных. Смотреть фото что такое связывание данных. Смотреть картинку что такое связывание данных. Картинка про что такое связывание данных. Фото что такое связывание данных

7. Обязательные и необязательные связи

Связи можно поделить на обязательные и необязательные.

7.1. Один ко многим

У одной биологической матери может быть много детей. У ребенка есть только одна биологическая мать.

А) У женщины необязательно есть свои дети. Соответственно, связь необязательна.
Б) У ребенка обязательно есть только одна биологическая мать – в таком случае, связь обязательна.

7.2. Один к одному

У одного человека может быть только один загранпаспорт. У одного загранпаспорта есть только один владелец.

А) Наличие загранпаспорта необязательно – его может и не быть у гражданина. Это необязательная связь.
Б) У загранпаспорта обязательно есть только один владелец. В этом случае, это уже обязательная связь.

7.3. Многие ко многим

Человек может инвестировать в акции разных компаний (многих). Инвесторами какой-то компании являются определенные люди (многие).

А) Человек может вообще не инвестировать свои деньги в акции.
Б) Акции компании мог никто не купить.

8. Как читать диаграммы?

Выше я приводил диаграммы созданных нами таблиц. Но для того, чтобы их понимать, нужно знать, как их «читать». Разберемся в этом на примере диаграммы из пункта 5.3.

что такое связывание данных. Смотреть фото что такое связывание данных. Смотреть картинку что такое связывание данных. Картинка про что такое связывание данных. Фото что такое связывание данных

Мы видим отношение один ко многим. Одной персоне принадлежит много телефонов.

9. Итоги

10. Задачи

Для лучшего усвоения материала предлагаю вам решить следующие задачи:

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *