Entity framework настройка связей
В предыдущей статье вы узнали о соглашениях Code-First по конфигурации столбцов таблицы базы данных. Здесь мы рассмотрим соглашения по созданию между таблицами в базе данных. Эти соглашения определяют то, как связываются классы в модели и настраиваются внешние ключи, определяющие эти связи. Для настройки этих конфигураций в основном используется Fluent API, а не аннотации данных.
Вы уже видели ранее использование некоторых связей между таблицами. Например, при рассмотрении примера в статье “Использование Code-First” мы создали следующую модель данных:
Code-First видит в этом примере, что вы определили навигационное свойство Orders в таблице Customer, ссылающееся на коллекцию объектов Order, что говорит о создании отношения один-ко-многим (one-to-many) между этими таблицами. Так же Code-First определит автоматически эту связь, создав внешний ключ для таблицы Order, привязанный к первичному ключу CustomerId таблицы Customer.
Далее мы опишем все соглашения, которые используются в Code-First для описания связей между таблицами.
Conventions
By default, a relationship will be created when there is a navigation property discovered on a type. A property is considered a navigation property if the type it points to cannot be mapped as a scalar type by the current database provider.
Relationships that are discovered by convention will always target the primary key of the principal entity. To target an alternate key, additional configuration must be performed using the Fluent API.
Полностью определенные связи
Наиболее распространенным шаблоном связей является определение свойств навигации на обоих концах связи и свойство внешнего ключа, определенное в зависимом классе сущностей.
Если пара свойств навигации найдена между двумя типами, они будут настроены как обратные свойства навигации одного и того же отношения.
Если зависимая сущность содержит свойство с именем, соответствующим одному из этих шаблонов, он будет настроен как внешний ключ:
В этом примере выделенные свойства будут использоваться для настройки связи.
Если свойство является первичным ключом или имеет тип, несовместимый с основным ключом, он не будет настроен как внешний ключ.
Обязательные и необязательные связи
Api Fluent можно использовать для настройки того, является ли связь обязательной или необязательной. В конечном счете это определяет, является ли свойство внешнего ключа обязательным или необязательным. Это наиболее полезно при использовании внешнего ключа теневого состояния. Если в классе сущности есть свойство внешнего ключа, необходимое отношение определяется в зависимости от того, является ли свойство внешнего ключа обязательным или необязательным (дополнительные сведения см. в разделе "Обязательные и необязательные свойства ").
Свойства внешнего ключа находятся в зависимом типе сущности, поэтому если они настроены по мере необходимости, это означает, что для каждой зависимой сущности требуется соответствующая сущность субъекта.
Вызов IsRequired(false) также делает свойство внешнего ключа необязательным, если оно не настроено в противном случае.
Создание сопоставления сопоставлений
Щелкните правой кнопкой мыши связь в области конструктора и выберите "Сопоставление таблиц". В окне сведений о сопоставлении отображается сопоставление сопоставлений.
Выберите таблицу, с которой будет сопоставлена ассоциация. В окне сведений о сопоставлении отображаются оба конца связи и ключевые свойства для типа сущности в каждом конце.
Для каждого свойства ключа щелкните поле "Столбец " и выберите столбец, с которым будет сопоставляться свойство.
Настройка вручную
Чтобы настроить связь в API Fluent, сначала определите свойства навигации, составляющие связь. HasOne или HasMany идентифицирует свойство навигации для типа сущности, на котором начинается конфигурация. Затем выполняется цепочка вызовов WithOne и WithMany определение обратной навигации. HasOne / WithOne используются для ссылочных свойств навигации и HasMany / WithMany используются для свойств навигации коллекции.
Заметки к данным можно использовать для настройки связывания свойств навигации по зависимым и основным сущностям. Обычно это делается при наличии нескольких пар свойств навигации между двумя типами сущностей.
Свойства зависимой сущности можно использовать только для [Обязательного], чтобы повлиять на необходимость связи. [Обязательный] для навигации из основной сущности обычно игнорируется, но это может привести к тому, что сущность станет зависимой.
Изменение сопоставления сопоставлений
- Щелкните правой кнопкой мыши связь в области конструктора и выберите "Сопоставление таблиц". В окне сведений о сопоставлении отображается сопоставление сопоставлений.
- Щелкните Карты в таблицы. Появится раскрывающийся список, содержащий все таблицы в модели хранения.
- Выберите таблицу, с которой будет сопоставлена ассоциация. В окне сведений о сопоставлении отображаются оба конца связи и ключевые свойства для типа сущности в каждом конце.
- Для каждого свойства ключа щелкните поле "Столбец " и выберите столбец, с которым будет сопоставляться свойство.
Principal key
If you want the foreign key to reference a property other than the primary key, you can use the Fluent API to configure the principal key property for the relationship. The property that you configure as the principal key will automatically be set up as an alternate key.
The order in which you specify principal key properties must match the order in which they are specified for the foreign key.
Связи в EF
В реляционных базах данных связи (также называемые связями) между таблицами определяются с помощью внешних ключей. Внешний ключ (FK) — это столбец или сочетание столбцов, которое применяется для принудительного установления связи между данными в двух таблицах. Обычно существует три типа связей: "один к одному", "один ко многим" и "многие ко многим". В связи "один ко многим" внешний ключ определяется в таблице, представляющей многие конце связи. Связь "многие ко многим" включает определение третьей таблицы (называемой таблицей соединения или соединения), первичный ключ которой состоит из внешних ключей из обеих связанных таблиц. В связи "один к одному" первичный ключ выступает дополнительно как внешний ключ, и для любой таблицы нет отдельного внешнего ключевого столбца.
На следующем рисунке показаны две таблицы, участвующие в связи "один ко многим". Таблица Course является зависимой таблицей, так как она содержит столбец DepartmentID , который связывает ее с таблицей Department .
В Entity Framework сущность может быть связана с другими сущностями через связь или связь. Каждая связь содержит два конца, которые описывают тип сущности и кратность типа (один, ноль или один или много) для двух сущностей в этой связи. Отношение может управляться справочным ограничением, описывающим, какой из конечных элементов отношения относится к основной роли, а какой к зависимой роли.
Свойства навигации позволяют перемещаться между двумя типами сущностей. Каждый объект может обладать свойством навигации для каждого отношения, в котором участвует. Свойства навигации позволяют перемещаться по связям в обоих направлениях и управлять ими, возвращая объект ссылки (если кратность равна одному или нулю или одному) или коллекции (если кратность имеет много). Вы также можете выбрать односторонняя навигация, в этом случае вы определяете свойство навигации только для одного из типов, участвующих в связи, а не для обоих.
Рекомендуется включить свойства в модель, которая сопоставляется с внешними ключами в базе данных. Включение свойств внешних ключей позволяет создавать или изменять отношение, изменяя значение внешнего ключа для зависимого объекта. Сопоставление такого типа называется сопоставлением на основе внешнего ключа. Использование внешних ключей еще более важно при работе с отключенными сущностями. Обратите внимание, что при работе с 1–1 или 1–0.. 1 связь, нет отдельного внешнего ключевого столбца, свойство первичного ключа действует как внешний ключ и всегда включается в модель.
Если внешние ключевые столбцы не включены в модель, сведения об ассоциации управляются как независимый объект. Связи отслеживаются с помощью ссылок на объекты, а не свойств внешнего ключа. Этот тип ассоциации называется независимой ассоциацией. Наиболее распространенным способом изменения независимой ассоциации является изменение свойств навигации, создаваемых для каждой сущности, участвующей в ассоциации.
В модели можно использовать один или оба типа сопоставлений. Однако если у вас есть чистое отношение "многие ко многим", связанное таблицей соединения, содержащей только внешние ключи, EF будет использовать независимую связь для управления такими отношениями "многие ко многим".
На следующем рисунке показана концептуальная модель, созданная с помощью конструктора Entity Framework. Модель содержит две сущности, участвующие в связи "один ко многим". Обе сущности имеют свойства навигации. Course является зависимой сущностью и имеет свойство внешнего ключа DepartmentID .
В следующем фрагменте кода показана та же модель, которая была создана с помощью Code First.
Каскадное удаление
API Fluent можно использовать для явной настройки поведения каскадного удаления для данной связи.
Подробные сведения о каждом из вариантов см. в разделе "Каскадное удаление ".
Foreign key
You can use the Fluent API to configure which property should be used as the foreign key property for a given relationship:
You can use the Fluent API to configure which properties should be used as the composite foreign key properties for a given relationship:
You can use the Data Annotations to configure which property should be used as the foreign key property for a given relationship. This is typically done when the foreign key property is not discovered by convention:
The [ForeignKey] annotation can be placed on either navigation property in the relationship. It does not need to go on the navigation property in the dependent entity class.
The property specified using [ForeignKey] on a navigation property doesn't need to exist on the dependent type. In this case the specified name will be used to create a shadow foreign key.
Shadow foreign key
You can use the string overload of HasForeignKey(. ) to configure a shadow property as a foreign key (see Shadow Properties for more information). We recommend explicitly adding the shadow property to the model before using it as a foreign key (as shown below).
Foreign key constraint name
By convention, when targeting a relational database, foreign key constraints are named FK___. For composite foreign keys, becomes an underscore separated list of foreign key property names.
You can also configure the constraint name as follows:
No foreign key property
While it is recommended to have a foreign key property defined in the dependent entity class, it is not required. If no foreign key property is found, a shadow foreign key property will be introduced with the name or if no navigation is present on the dependent type.
In this example, the shadow foreign key is BlogId because prepending the navigation name would be redundant.
If a property with the same name already exists, then the shadow property name will be suffixed with a number.
Definition of terms
There are a number of terms used to describe relationships
Dependent entity: This is the entity that contains the foreign key properties. Sometimes referred to as the 'child' of the relationship.
Principal entity: This is the entity that contains the primary/alternate key properties. Sometimes referred to as the 'parent' of the relationship.
Principal key: The properties that uniquely identify the principal entity. This may be the primary key or an alternate key.
Foreign key: The properties in the dependent entity that are used to store the principal key values for the related entity.
Navigation property: A property defined on the principal and/or dependent entity that references the related entity.
Collection navigation property: A navigation property that contains references to many related entities.
Reference navigation property: A navigation property that holds a reference to a single related entity.
Inverse navigation property: When discussing a particular navigation property, this term refers to the navigation property on the other end of the relationship.
Self-referencing relationship: A relationship in which the dependent and the principal entity types are the same.
The following code shows a one-to-many relationship between Blog and Post
Post is the dependent entity
Blog is the principal entity
Blog.BlogId is the principal key (in this case it is a primary key rather than an alternate key)
Post.BlogId is the foreign key
Post.Blog is a reference navigation property
Blog.Posts is a collection navigation property
Post.Blog is the inverse navigation property of Blog.Posts (and vice versa)
Limitations
When there are multiple navigation properties defined between two types (that is, more than just one pair of navigations that point to each other) the relationships represented by the navigation properties are ambiguous. You will need to manually configure them to resolve the ambiguity.
Управление параллелизмом
В внешних и независимых сопоставлениях проверки параллелизма основаны на ключах сущностей и других свойствах сущностей, определенных в модели. При использовании конструктора EF для создания модели задайте ConcurrencyMode для атрибута фиксированное значение, чтобы указать, что свойство должно проверяться на наличие параллелизма. При использовании Code First для определения модели используйте заметку ConcurrencyCheck о свойствах, которые требуется проверить на наличие параллелизма. При работе с Code First можно также использовать заметку TimeStamp , чтобы указать, что свойство должно проверяться на наличие параллелизма. В данном классе может быть только одно свойство метки времени. Code First сопоставляет это свойство с полем, не допускаемым значением NULL, в базе данных.
Рекомендуется всегда использовать связь внешнего ключа при работе с сущностями, участвующими в проверке параллелизма и разрешении.
Ключ субъекта
Если внешний ключ будет ссылаться на свойство, отличное от первичного ключа, можно использовать API Fluent для настройки свойства ключа субъекта для связи. Свойство, которое вы настраиваете в качестве основного ключа, будет автоматически настроено в качестве альтернативного ключа.
Порядок, в котором указываются свойства ключа субъекта, должен соответствовать порядку, в котором они указаны для внешнего ключа.
Создание и изменение связей
При изменении связи внешнего ключа состояние зависимого объекта с состоянием EntityState.Unchanged изменяется EntityState.Modified . В независимой связи изменение связи не обновляет состояние зависимого объекта.
В следующих примерах показано, как использовать свойства внешнего ключа и свойства навигации для связывания связанных объектов. С помощью связей внешнего ключа можно использовать любой метод для изменения, создания или изменения связей. Для независимых сопоставлений нельзя использовать свойство внешнего ключа.
Присвоив новое значение свойству внешнего ключа, как показано в следующем примере.
Следующий код удаляет связь, задав внешнему ключу значение NULL. Обратите внимание, что свойство внешнего ключа должно иметь значение NULL.
Если ссылка находится в добавленном состоянии (в этом примере объект course), свойство навигации ссылки не будет синхронизировано со значениями ключей нового объекта до вызова SaveChanges. Синхронизация не выполняется, поскольку контекст объекта не содержит постоянных ключей для добавленных объектов, пока они не будут сохранены. Если новые объекты должны быть полностью синхронизированы сразу после установки связи, используйте один из следующих методов.*
С помощью присваивания нового объекта свойству навигации. Следующий код создает связь между курсом и курсом department . Если объекты присоединены к контексту, он course также добавляется в коллекцию department.Courses , а соответствующее свойство course внешнего ключа объекта устанавливается в значение свойства ключа отдела.
Путем удаления или добавления объекта в коллекцию сущностей. Например, можно добавить объект типа Course в коллекцию department.Courses . Эта операция создает связь между определенным курсом и определенным department . Если объекты присоединены к контексту, ссылка на отдел и свойство внешнего ключа объекта курса будут заданы соответствующим department образом.
С помощью ChangeRelationshipState метода можно изменить состояние указанной связи между двумя объектами сущности. Этот метод чаще всего используется при работе с N-уровневыми приложениями и независимой ассоциацией (ее нельзя использовать с ассоциацией внешнего ключа). Кроме того, чтобы использовать этот метод, необходимо выполнить раскрывающийся список ObjectContext , как показано в примере ниже.
В следующем примере существует связь "многие ко многим" между инструкторами и курсами. ChangeRelationshipState Вызов метода и передача EntityState.Added параметра позволяет узнать SchoolContext , что связь была добавлена между двумя объектами:
Обратите внимание, что при обновлении (а не только добавлении) связи необходимо удалить старую связь после добавления новой:
Внешний ключ
С помощью API Fluent можно настроить, какое свойство следует использовать в качестве свойства внешнего ключа для данной связи:
Api Fluent можно использовать для настройки свойств составного внешнего ключа для данной связи:
Заметки к данным можно использовать для настройки свойства внешнего ключа для данной связи. Обычно это делается, если свойство внешнего ключа не обнаруживается по соглашению:
Заметку [ForeignKey] можно поместить в любое свойство навигации в связи. Не нужно переходить к свойству навигации в зависимом классе сущностей.
Свойство, указанное в [ForeignKey] свойстве навигации, не требуется существовать в зависимом типе. В этом случае указанное имя будет использоваться для создания теневого внешнего ключа.
Теневой внешний ключ
Вы можете использовать строковую перегрузку HasForeignKey(. ) для настройки свойства тени в качестве внешнего ключа (дополнительные сведения см. в разделе "Свойства тени "). Мы рекомендуем явно добавить свойство тени в модель, прежде чем использовать его в качестве внешнего ключа (как показано ниже).
Имя ограничения внешнего ключа
По соглашению при выборе реляционной базы данных ограничения внешнего ключа именуются FK___foreign key property name_. Для составных внешних ключей свойства внешнего ключа становится разделенным списком имен свойств внешнего ключа подчеркивания.
Можно также настроить имя ограничения следующим образом:
Other relationship patterns
Каскадное удаление
По соглашению каскадное удаление будет иметь значение Cascade для необходимых связей и ClientSetNull для необязательных связей. Каскад означает, что зависимые сущности также удаляются. ClientSetNull означает, что зависимые сущности, которые не загружаются в память, останутся неизменными и должны быть удалены вручную или обновлены, чтобы указать на действительную сущность субъекта. Для сущностей, загруженных в память, EF Core попытается задать для свойств внешнего ключа значение NULL.
Дополнительные сведения о различных способах удаления и значениях по умолчанию, используемых в соглашении, см. в статье "Каскадное удаление ".
Работа с перекрывающимися ключами
Перекрывающиеся ключи представляют собой составные ключи, некоторые из свойств в которых также являются частью другого ключа в сущности. Для независимых сопоставлений использовать перекрывающиеся ключи нельзя. Для изменения сопоставления на основе внешнего ключа, содержащей перекрывающиеся ключи, рекомендуется изменять значения внешнего ключа вместо использования ссылок на объекты.
Создание ассоциации
Щелкните правой кнопкой мыши пустую область области конструктора, наведите указатель мыши на кнопку "Добавить новую" и выберите "Связь. ".
Заполните параметры связи в диалоговом окне добавления ассоциации .
Вы можете не добавлять свойства навигации или свойства внешнего ключа в сущности в конце ассоциации, снимите флажки **Свойство навигации **и **Добавить свойства внешнего ключа в сущности**". При добавлении одного свойства навигации ассоциацию можно будет перемещать только в одном направлении. При добавлении свойств навигации необходимо добавить свойства внешнего ключа, чтобы обеспечить доступ к сущностям в элементах ассоциации.
Работа с обратными навигационными свойствами
Пока мы использовали по одному навигационному свойству между двумя классами модели, Code-First понимал, как настроить отношения между ними. Существует такие случаи, когда между двумя таблицами базы данных нужно определить несколько отношений. Например, таблица Customers могла бы ссылаться на все заказы, на обработанные заказы (которые оплатил покупатель) и необработанные заказы. Логичнее всего решить данную проблему, это просто добавить новый столбец, например IsProcess, в таблицу Orders, который имел бы логическое значение и указывал бы на то, обработан заказ или нет. Но также эту проблему можно решить использовав три внешних ключа, связывающих эти таблицы.
В модели классов это решение будет выглядеть следующим образом:
В данном примере Code-First не сможет автоматически распознать связь между навигационными свойствами этих классов. Если вы выполните этот пример, то увидите, что в созданной таблице Orders было добавлено пять внешних ключей – по одному для каждого несвязанного навигационного свойства, и один ключ для связанных свойств Orders и Customer (если вы удалите настройку Fluent API, показанную ранее, в которой мы привязали эти свойства и указали внешний ключ, то Code-First сгенерирует 6 внешних ключей).
Согласно соглашениям, Code-First может самостоятельно определить двунаправленную связь между таблицами, только когда существует всего одна пара навигационных свойств. В нашем примере их несколько, поэтому Code-First создаст по одному внешнему ключу для каждого навигационного свойства.
Теперь будет создано три внешних ключа, как и требовалось:
Использование навигационных свойств
Как вы видели, Code-First автоматически добавляет отношения между таблицами если видит навигационные свойства в коде модели и, необязательно, явно указанные внешние ключи. Мы подробно опишем использование внешних ключей чуть позже, а сейчас давайте остановимся на определении отношений между таблицами без внешних ключей.
Отношения между таблицами можно определить в модели только за счет использования навигационных свойств, которые могут быть указаны в обеих таблицах (двусторонняя связь, как показано в примере выше) или в одной таблице (односторонняя связь). Ниже описаны некоторые соглашения Code-First при использовании навигационных свойств:
Code-First также будет предполагать связь один-ко-многим, если навигационное свойство используется только в одной таблице, вне зависимости от типа этого свойства (т.е. если используется односторонняя связь).
Если в обеих таблицах навигационные свойства имеют тип коллекций, то Code-First предполагает наличие связи между ними многие-ко-многим (many-to-many).
Если в обеих таблицах навигационные свойства представлены в виде ссылок друг на друга, то Code-First предполагает отношение между таблицами один-к-одному (one-to-one).
В случае реализации отношения один-к-одному, вы должны будете предоставить некоторую дополнительную информацию, чтобы Code-First знал, какая сущность является основной, а какая зависимой. Если в таблицах явно не указан внешний ключ, то Code-First смоделирует отношение один-или-ноль-к-одному (zero-or-one-to-one, 0..1-1), т.е. добавление данных в главную таблицу, необязательно должно вести к добавлению данных в зависимую таблицу.
Посмотрев пример нашей модели, показанной выше, можно проследить использование этих соглашений на классах Customer и Order. Например, Code-First автоматически создаст отношение между таблицами один-ко-многим, т.к. мы использовали тип коллекции в одной таблице и простую ссылку в другой. Также можно догадаться, что в отношении этих таблиц Customer будет главной, а Order зависимой, т.е. мы можем вставить данные заказчика в таблицу Customer, не добавляя при этом для него заказы. И наоборот, в таблицу Order мы можем вставить только заказ, привязанный к конкретному покупателю.
Стоит также сказать, что без явного указания внешних ключей в коде модели, Code-First будет генерировать эти ключи автоматически, используя имя, сочетающие в себе название базовой таблицы и первичного ключа этой таблицы. Например, для таблицы Order будет сгенерирован внешний ключ Customer_CustomerId.
Большую часть конфигурации по настройке навигационных свойств мы можем выполнить с помощью Fluent API. Некоторые настройки можно выполнить и с помощью аннотаций данных, хотя в данном случае этот подход намного более ограничен, чем использование Fluent API. Например, мы можем указать для автоматически генерируемого внешнего ключа, чтобы он не поддерживал значения NULL:
Если вы запустите приложение и обновите структуру базы данных, то обнаружите, что Code-First изменил тип внешнего ключа Customer_CustomerId – теперь он не может поддерживать значения NULL:
Напомню, что мы используем в качестве примера приложение, созданное в статье “Использование Code-First” и для воссоздания базы данных при изменении модели требуется либо ее ручное удаление всякий раз, когда база данных изменилась, либо использование настроек Code-First по автоматическому обнаружению изменений в модели.
Настройка отношений с помощью Fluent API может показаться несколько запутанной, если вы не потратите некоторое время, чтобы понять основные идеи. При использовании аннотаций данных для настройки отношений вы просто устанавливаете атрибуты для навигационных свойств в коде модели. Это сильно отличается от подхода с Fluent API, где вы должны в буквальном смысле настроить отношения между таблицами. Для этого используется следующий общий шаблон (он не зависит от того, хотите ли вы использовать одностороннюю или двустороннюю связь):
Параметр Multiplicity в этом шаблоне указывает на окончание используемых методов Has… и With…, он может иметь следующие значения: Optional (навигационное свойство может иметь один или ноль экземпляров), Required (навигационное свойство может иметь только один экземпляр) и Many (навигационное свойство содержит коллекцию экземпляров).
Соответственно Entity Framework определяет следующий набор методов, определяющих настройки первичных навигационных свойств:
Для настройки отношений во второй таблице, используются следующие методы:
При вызове этих методов в качестве параметра, им передается делегат, в котором указывается навигационное свойство. При использовании односторонней связи (когда в одной из таблиц отсутствует навигационное свойство), можно вызвать соответствующий метод без параметров. Ниже показан пример настройки навигационных свойств для наших таблиц, который соответствует автоматическим соглашениям Code-First. Т.е. фактически он создает связь один-ко-многим между нашими таблицами, где таблица Customer является главной:
Ранее мы показали, как с помощью аннотаций данных можно ограничить поддержку NULL значений для автоматически сгенерированного внешнего ключа. Давайте реализуем это с помощью Fluent API:
В этом примере мы просто поменяли вызов метода WithOptional() на WithRequired(). Если вы запустите пример и посмотрите на структуру таблицы Orders, то увидите, что ее структура аналогична той, которая показана на первом рисунке в статье, когда мы использовали атрибуты метаданных. На рисунке ниже наглядно показано, как выполняется этот запрос:
Включение свойств внешнего ключа в сущности (ссылочных ограничений)
Рекомендуется всегда предоставлять внешние ключи для связей в сущностях. Entity Framework использует референциальное ограничение, чтобы определить, что свойство выступает в качестве внешнего ключа для связи.
Если при создании связи установлен флажок Add foreign key properties to the Entity,this referential constraint was added for you.
При использовании конструктора EF для добавления или изменения ссылочного ограничения конструктор EF добавляет или изменяет элемент ReferentialConstraint в содержимом CSDL-файла edmx.
Дважды щелкните ассоциацию, которую необходимо изменить. Откроется диалоговое окно "Ограничение ссылки ".
В раскрывающемся списке "Субъект" выберите основную сущность в референциальном ограничении. Свойства ключа сущности добавляются в список ключей субъекта в диалоговом окне.
В раскрывающемся списке "Зависимые " выберите зависимую сущность в референциальном ограничении.
Для каждого ключа субъекта, имеющего зависимый ключ, выберите соответствующий зависимый ключ из раскрывающихся списков в столбце " Зависимый ключ ".
Один к одному
Один к одному отношениям имеет свойство навигации ссылок с обеих сторон. Они следуют тем же соглашениям, что и связи "один ко многим", но уникальный индекс вводится в свойстве внешнего ключа, чтобы гарантировать, что только один зависимый связан с каждым субъектом.
EF выберет одну из сущностей в зависимости от его способности обнаруживать свойство внешнего ключа. Если неправильная сущность выбрана в качестве зависимой, вы можете использовать API Fluent для исправления этой ошибки.
При настройке связи с API Fluent используются HasOne методы и WithOne методы.
При настройке внешнего ключа необходимо указать зависимый тип сущности. Обратите внимание на универсальный параметр, предоставленный HasForeignKey в приведенном ниже списке. В связи "один ко многим" ясно, что сущность со ссылкой является зависимой, а одна с коллекцией является основной. Но это не так в связи "один к одному" - следовательно, необходимость явно определить его.
Зависимые стороны считаются необязательными по умолчанию, но могут быть настроены по мере необходимости. Однако EF не будет проверять, была ли предоставлена зависимой сущностью, поэтому эта конфигурация будет иметь значение только при условии, что сопоставление базы данных позволяет применять ее. Типичным сценарием для этого являются ссылочные типы, использующие разделение таблиц по умолчанию.
При такой конфигурации столбцы, соответствующие этому параметру ShippingAddress , будут помечены как не допускающие значения NULL в базе данных.
Если вы используете вызов IsRequired ссылочных типов, не допускающих значения NULL, не требуется.
Возможность настройки необходимости зависимого в EF Core 5.0.
Настройка внешних ключей в обход соглашениям Code-First
Иногда может возникнуть вопрос, что происходит, если имя вашего внешнего ключа не соответствует соглашениям Code-First? Например, вы могли бы использовать в таблице Order внешний ключ с именем UserId, как показано ниже:
Если вы запустите приложение и воссоздадите базу данных, то увидите, что Code-First проигнорировал поле UserId и создал автоматически генерируемый внешний ключ Customer_CustomerId, а поле UserId было добавлено как обычный столбец. Вы можете решить эту проблему используя атрибут ForeignKey в классе модели данных, как показано в примере:
В конструкторе этого атрибута указывается имя навигационного свойства, если оно имеется в классе модели. Альтернативным способом является применение атрибута ForeignKey к навигационному свойству:
В данном случае в конструкторе указывается имя свойства, являющегося внешним ключом. В Fluent API используется специальный метод HasForeignKey(), как показано в примере ниже:
Создание и удаление ассоциаций
Создание связи с конструктором EF обновляет содержимое модели edmx-файла. После создания связи необходимо создать сопоставления для ассоциации (рассматривается далее в этом разделе).
В этом разделе предполагается, что вы уже добавили сущности, которые вы хотите создать связь между моделью.
Single navigation property
Including just one navigation property (no inverse navigation, and no foreign key property) is enough to have a relationship defined by convention. You can also have a single navigation property and a foreign key property.
Загрузка связанных объектов
В Entity Framework обычно используются свойства навигации для загрузки сущностей, связанных с возвращаемой сущностью определенной ассоциацией. Дополнительные сведения см. в разделе "Загрузка связанных объектов".
В сопоставлении на основе внешнего ключа при загрузке связанного конечного элемента зависимого объекта связанный объект загружается на основе значения внешнего ключа зависимого объекта, находящегося на момент загрузки в памяти:
В независимом сопоставлении связанный конечный элемент зависимого объекта запрашивается на основе значения внешнего ключа зависимого объекта, находящегося на момент загрузки в базе данных. Однако если связь была изменена, а ссылочное свойство зависимого объекта указывает на другой основной объект, загруженный в контексте объекта, Entity Framework попытается создать связь, так как она определена на клиенте.
Required and optional relationships
You can use the Fluent API to configure whether the relationship is required or optional. Ultimately this controls whether the foreign key property is required or optional. This is most useful when you are using a shadow state foreign key. If you have a foreign key property in your entity class then the requiredness of the relationship is determined based on whether the foreign key property is required or optional (see Required and Optional properties for more information).
The foreign key properties are located on the dependent entity type, so if they are configured as required it means that every dependent entity is required to have a corresponding principal entity.
Calling IsRequired(false) also makes the foreign key property optional unless it's configured otherwise.
Без свойства навигации
Необязательно указывать свойство навигации. Вы можете просто предоставить внешний ключ на одной стороне связи.
Изменение и удаление свойств навигации
Свойства навигации — это свойства ярлыка, используемые для поиска сущностей в конце ассоциации в модели. Свойства навигации могут быть созданы при создании ассоциации между двумя типами сущностей.
В этой статье приводится обзор того, как Entity Framework управляет связями между сущностями. В нем также приводятся некоторые рекомендации по сопоставлению и манипулирования связями.
Many-to-many
Many-to-many relationships require a collection navigation property on both sides. They will be discovered by convention like other types of relationships.
The way this relationship is implemented in the database is by a join table that contains foreign keys to both Post and Tag . For example this is what EF will create in a relational database for the above model.
Internally, EF creates an entity type to represent the join table that will be referred to as the join entity type. Dictionary is currently used for it to handle any combination of foreign key properties, see property bag entity types for more information. More than one many-to-many relationships can exist in the model, therefore the join entity type must be given a unique name, in this case PostTag . The feature that allows this is called shared-type entity type.
The CLR type used for join entity types by convention may change in future releases to improve performance. Do not depend on the join type being Dictionary unless this has been explicitly configured, as described in the next section.
The many-to-many navigations are called skip navigations as they effectively skip over the join entity type. If you are employing bulk configuration all skip navigations can be obtained from GetSkipNavigations.
Join entity type configuration
It is common to apply configuration to the join entity type. This action can be accomplished via UsingEntity .
Model seed data can be provided for the join entity type by using anonymous types. You can examine the model debug view to determine the property names created by convention.
Additional data can be stored in the join entity type, but for this it's best to create a bespoke CLR type. When configuring the relationship with a custom join entity type both foreign keys need to be specified explicitly.
Joining relationships configuration
EF uses two one-to-many relationships on the join entity type to represent the many-to-many relationship. You can configure these relationships in the UsingEntity arguments.
The ability to configure many-to-many relationships was introduced in EF Core 5.0, for previous version use the following approach.
Indirect many-to-many relationships
You can also represent a many-to-many relationship by just adding the join entity type and mapping two separate one-to-many relationships.
Support for scaffolding many-to-many relationships from the database is not yet added. See tracking issue.
Связь определяет, как две сущности связаны друг с другом. В реляционной базе данных это представляется ограничением внешнего ключа.
Большинство примеров в этой статье используют связь "один ко многим" для демонстрации концепций. Примеры связей "один к одному" и "многие ко многим" см. в разделе "Другие шаблоны отношений " в конце статьи.
Without navigation property
You don't necessarily need to provide a navigation property. You can simply provide a foreign key on one side of the relationship.
Нет свойства внешнего ключа
Хотя рекомендуется иметь свойство внешнего ключа, определенное в зависимом классе сущностей, это не обязательно. Если свойство внешнего ключа не найдено, свойство теневого внешнего ключа будет введено с именем или если навигация отсутствует в зависимом типе.
В этом примере внешний ключ тени заключается в BlogId том, что добавление имени навигации будет избыточным.
Если свойство с таким же именем уже существует, имя теневой свойства будет суффиксировано числом.
Настройка или сопоставление связей
На остальной части этой страницы показано, как получить доступ к данным и управлять ими с помощью связей. Сведения о настройке связей в модели см. на следующих страницах.
- Сведения о настройке связей в Code First см. в разделе "Заметки к данным" и API Fluent — связи.
- Сведения о настройке связей с помощью конструктора Entity Framework см. в разделе "Связи" с конструктором EF.
Указание внешних ключей
Ранее мы рассмотрели, как реализовать отношения между таблицами без прямого использования внешних ключей. Например, класс Order содержит свойство-ссылку на класс Customer, но при этом в этом классе не определено свойство, которое будет использоваться в качестве внешнего ключа для связи между таблицами. В этом случае мы видели, что Code-First автоматически сгенерирует внешний ключ за вас. Теперь давайте рассмотрим, что происходит, если мы явно задаем внешний ключ.
Первое что мы сделаем, это добавим новое свойство CustomerId в класс модели Order:
Запустите приложение. Code-First поймет, что вы внесли изменения в модель и воссоздаст базу данных. Если вы рассмотрите структуру столбцов таблицы Order, то заметите, что Code-First автоматически распознал поле CustomerId как внешний ключ и заменил автоматически генерируемый ключ Customer_CustomerId на CustomerId:
Как вы понимаете, Code-First использует определенные соглашения при поиске внешнего ключа в свойствах модели. Эти правила основаны на имени свойства и придерживаются следующих шаблонов:
В нашем случае имя свойства CustomerId подходит под первое правило, т.к. в главной таблице Customer используется одноименное свойство, которое является первичным ключом таблицы. Также стоит отметить, что Code-First не чувствителен к регистру символов при поиске внешнего ключа, т.е. если бы в таблице Order у нас было бы свойство CusToMeRId, то Code-First автоматически бы распознал его как внешний ключ.
К данному моменту может возникнуть вопрос, зачем может понадобиться явное определение внешних ключей в классе модели, если Code-First способен автоматически создавать эти ключи? Ответом на этот вопрос будет то, что иногда гораздо удобней получить доступ к родительскому объекту в коде через внешний ключ, нежели чем через ссылку. Например, в коде вы могли бы создать новый объект Order и указать через ссылку объект Customer, к которому он должен принадлежать:
Очевидно, для того, чтобы загрузить объект Customer в экземпляр myCustomer, вам необходимо будет сначала обратиться к базе данных. Использование внешнего ключа позволяет просто указать идентификатор заказчика не ссылаясь на него. Чтобы получить идентификатор заказчика, зачастую нужно также обратиться к базе данных, но бывают случаи, когда у вас есть доступ к значению ключа этого объекта. Например, если мы знаем что заказ myOrder принадлежит заказчику с идентификатором 5, мы могли бы использовать внешний ключ вместо ссылки на объект:
Кроме того, при использовании ссылки иногда возникает более серьезная ошибка. Entity Framework отслеживает состояние объектов сущностных классов и при их изменении помечает объект, изменяя свойство DbEntityEntry.State. Если вы создадите новый объект myOrder, укажите в нем ссылку на уже существующий в памяти объект myCustomer и попытаетесь сохранить объект myCustomer в базе данных, то EF пометит состояние этого объекта как Added, а не Modified, т.к. в коде изменился список заказов, связанных с этим покупателем и EF предполагает, что был создан новый покупатель. В результате в таблицу будет добавлен новый заказчик, хотя предполагалось просто добавить заказ для уже существующего заказчика. Эту проблему можно избежать либо сохранив в базе данных только объект myOrder, либо используя внешний ключ.
Есть еще один момент, который нужно упомянуть при обсуждении соглашений Code-First по внешним ключам. Когда ранее мы не использовали внешних ключей, Code-First автоматически генерировал ключ, который поддерживал значения NULL. Если вы взгляните на рисунок выше, то увидите, что внешний ключ CustomerId в таблице Order имеет не обнуляемый тип NOT NULL, поэтому вы не сможете сохранить новый заказ не указав идентификатор покупателя (используя внешний ключ или ссылку). Тем не менее, можно явно указать, что внешний ключ должен поддерживать значения NULL. Для этого измените тип свойства CustomerId в классе модели Order на обнуляемый тип данных:
Итак, из всего сказанного выше, можно сделать вывод, что Code First позволяет определять отношения без использования внешних ключей в ваших классах. Тем не менее, разработчики иногда сталкиваются с некоторыми запутанными ошибками, когда работают с моделями, не имеющими внешних ключей, как было показано ранее.
Общие сведения об сопоставлениях
При проектировании модели с помощью конструктора EF EDMX-файл представляет вашу модель. В EDMX-файле элемент Association определяет связь между двумя типами сущностей. Ассоциация должна указывать типы сущностей, которые участвуют в связи, и возможное количество типов сущностей на каждом конце связи, которое называется кратностью. Кратность элемента ассоциации может иметь значение «один» (1), «ноль или один» (0..1) или «многие» (*). Эти сведения указываются в двух дочерних элементах End .
Во время выполнения экземпляры типа сущности в одном конце связи можно получить через свойства навигации или внешние ключи (если вы решили предоставить внешние ключи в сущностях). При использовании внешних ключей связь между сущностями управляется элементом ReferentialConstraint (дочерним элементом элемента Association ). Рекомендуется всегда предоставлять внешние ключи для связей в сущностях.
В "многие ко многим" (*:*) нельзя добавлять внешние ключи к сущностям. В связи *:* сведения об ассоциации управляются независимым объектом.
Сведения о элементах CSDL (ReferentialConstraint, Association и т. д.) см. в спецификации CSDL.
Использование однонаправленной связи между таблицами
В предыдущих примерах мы рассмотрели способы создания двунаправленных связей между таблицами, т.е. когда в обоих классах модели определяется навигационное свойство. Тем не менее определение пары навигационных свойств не является обязательным при работе с Entity Framework. В нашей модели мы можем указать ссылку только в одном классе, например, в классе Customer оставить ссылку на коллекцию объектов Order, а в классе Order удалить ссылку на Customer:
В этом примере мы не стали удалять внешний ключ CustomerId, благодаря чему, Entity Framework четко определяет связь между таблицами с использованием этого ключа, используя соглашения, описанные выше. Теперь давайте сделаем еще один шаг и удалим внешний ключ из таблицы Order:
Ранее мы уже сказали, что по соглашению Code-First сгенерирует автоматически внешний ключ, если он не объявлен явно в классе модели. Это же соглашение работает, если мы используем однонаправленную связь между таблицами. Класс Customer по прежнему имеет навигационное свойство, определяющие его отношение с Order, поэтому будет генерироваться внешний ключ с именем Customer_CustomerId в таблице Orders.
Что будет если мы захотим удалить оба навигационных свойства, а использовать для связи явно заданный внешний ключ? Сама платформа Entity Framework поддерживает этот сценарий, но не подход Code-First. В Code-First требуется для создания отношений определить как минимум одно навигационное свойство, иначе свойство модели, которое мы планировали использовать как внешний ключ, будет просто преобразовано в столбец в таблице и отношения между таблицами не будут созданы.
Теперь давайте рассмотрим случай, когда мы явно указываем внешний ключ в зависимой таблице и при этом желаем изменить его имя, которое не будет соответствовать соглашениям Code-First по именованию внешних ключей, например:
Как мы описывали раньше, чтобы явно указать классу Order, что UserId является внешним ключом, можно использовать атрибут ForeignKey и передать ему имя навигационного свойства в параметре. Что делать, если мы используем одностороннюю связь и в классе Order не используем навигационное свойство?
Для решения этой проблемы мы можем использовать этот атрибут в главной таблице к навигационному свойству Orders или использовать Fluent API, как показано в примере ниже:
Обратите внимание, что при использовании Fluent API в вызове метода WithRequired() мы не передаем параметр делегата с выбором навигационного свойства из модели, т.к. используем одностороннюю связь и у нас отсутствует навигационное свойство в классе Order.
A relationship defines how two entities relate to each other. In a relational database, this is represented by a foreign key constraint.
Most of the samples in this article use a one-to-many relationship to demonstrate concepts. For examples of one-to-one and many-to-many relationships see the Other Relationship Patterns section at the end of the article.
Single navigation property
If you only have one navigation property then there are parameterless overloads of WithOne and WithMany . This indicates that there is conceptually a reference or collection on the other end of the relationship, but there is no navigation property included in the entity class.
Manual configuration
To configure a relationship in the Fluent API, you start by identifying the navigation properties that make up the relationship. HasOne or HasMany identifies the navigation property on the entity type you are beginning the configuration on. You then chain a call to WithOne or WithMany to identify the inverse navigation. HasOne / WithOne are used for reference navigation properties and HasMany / WithMany are used for collection navigation properties.
You can use the Data Annotations to configure how navigation properties on the dependent and principal entities pair up. This is typically done when there is more than one pair of navigation properties between two entity types.
You can only use [Required] on properties on the dependent entity to impact the requiredness of the relationship. [Required] on the navigation from the principal entity is usually ignored, but it may cause the entity to become the dependent one.
Другие шаблоны связей
Fully defined relationships
The most common pattern for relationships is to have navigation properties defined on both ends of the relationship and a foreign key property defined in the dependent entity class.
If a pair of navigation properties is found between two types, then they will be configured as inverse navigation properties of the same relationship.
If the dependent entity contains a property with a name matching one of these patterns then it will be configured as the foreign key:
In this example the highlighted properties will be used to configure the relationship.
If the property is the primary key or is of a type not compatible with the principal key then it won't be configured as the foreign key.
Cascade delete
You can use the Fluent API to configure the cascade delete behavior for a given relationship explicitly.
See Cascade Delete for a detailed discussion of each option.
создавать и изменять сопоставления ассоциаций
Можно указать, как сопоставление сопоставляется с базой данных в окне сведений о сопоставлении конструктора EF.
Вы можете сопоставить сведения только для сопоставлений, у которых нет указанного ссылочного ограничения. Если задано ссылочного ограничения, свойство внешнего ключа включается в сущность, и для управления столбцом, с которым сопоставляется внешний ключ, можно использовать сведения о сопоставлении сущности.
Синхронизация изменений между внешними ключами и свойствами навигации
При изменении связи объектов, присоединенных к контексту, с помощью одного из описанных выше методов Entity Framework необходимо сохранить внешние ключи, ссылки и коллекции в синхронизации. Entity Framework автоматически управляет этой синхронизацией (также называемой исправлением связей) для сущностей POCO с прокси-серверами. Дополнительные сведения см. в разделе "Работа с прокси-серверами".
При использовании сущностей POCO без прокси-серверов необходимо убедиться, что метод DetectChanges вызывается для синхронизации связанных объектов в контексте. Обратите внимание, что следующие API автоматически активируют вызов DetectChanges .
- DbSet.Add
- DbSet.AddRange
- DbSet.Remove
- DbSet.RemoveRange
- DbSet.Find
- DbSet.Local
- DbContext.SaveChanges
- DbSet.Attach
- DbContext.GetValidationErrors
- DbContext.Entry
- DbChangeTracker.Entries
- Выполнение запроса LINQ к объекту DbSet
One-to-one
One to one relationships have a reference navigation property on both sides. They follow the same conventions as one-to-many relationships, but a unique index is introduced on the foreign key property to ensure only one dependent is related to each principal.
EF will choose one of the entities to be the dependent based on its ability to detect a foreign key property. If the wrong entity is chosen as the dependent, you can use the Fluent API to correct this.
When configuring the relationship with the Fluent API, you use the HasOne and WithOne methods.
When configuring the foreign key you need to specify the dependent entity type - notice the generic parameter provided to HasForeignKey in the listing below. In a one-to-many relationship it is clear that the entity with the reference navigation is the dependent and the one with the collection is the principal. But this is not so in a one-to-one relationship - hence the need to explicitly define it.
The dependent side is considered optional by default, but can be configured as required. However EF will not validate whether a dependent entity was provided, so this configuration will only make a difference when the database mapping allows it to be enforced. A common scenario for this are reference owned types that use table splitting by default.
With this configuration the columns corresponding to ShippingAddress will be marked as non-nullable in the database.
If you are using non-nullable reference types calling IsRequired is not necessary.
The ability to configure whether the dependent is required was introduced in EF Core 5.0.
Cascade delete
By convention, cascade delete will be set to Cascade for required relationships and ClientSetNull for optional relationships. Cascade means dependent entities are also deleted. ClientSetNull means that dependent entities that are not loaded into memory will remain unchanged and must be manually deleted, or updated to point to a valid principal entity. For entities that are loaded into memory, EF Core will attempt to set the foreign key properties to null.
See the Required and Optional Relationships section for the difference between required and optional relationships.
See Cascade Delete for more details about the different delete behaviors and the defaults used by convention.
Соглашения
По умолчанию связь создается при обнаружении свойства навигации в типе. Свойство считается свойством навигации, если тип, на который он указывает, невозможно сопоставить как скалярный тип текущим поставщиком базы данных.
Связи, обнаруженные по соглашению, всегда будут нацелены на первичный ключ основной сущности. Чтобы выбрать альтернативный ключ, необходимо выполнить дополнительную настройку с помощью API Fluent.
"Много ко многим"
Для связей "многие ко многим" требуется свойство навигации по коллекции с обеих сторон. Они будут обнаружены по соглашению, как и другие типы отношений.
Способ реализации этой связи в базе данных — таблица соединения, содержащая внешние ключи для обоих Post и Tag . Например, это то, что EF создаст в реляционной базе данных для приведенной выше модели.
Во внутренней среде EF создает тип сущности для представления таблицы соединения, которая будет называться типом сущности соединения. Dictionary в настоящее время используется для обработки любого сочетания свойств внешнего ключа, см. дополнительные сведения о типах сущностей контейнера свойств . В модели может существовать несколько связей "многие ко многим", поэтому тип сущности соединения должен иметь уникальное имя в данном случае PostTag . Эта функция называется типом сущности общего типа.
Тип CLR, используемый для типов сущностей соединения по соглашению, может измениться в будущих выпусках, чтобы повысить производительность. Не зависит от типа Dictionary соединения, если это не было явно настроено, как описано в следующем разделе.
Переходы "многие ко многим" называются пропусками навигаций, так как они фактически пропускают тип сущности соединения. Если вы используете массовую конфигурацию, все переходы по пропуску можно получить из GetSkipNavigations.
Присоединение к конфигурации типа сущности
Обычно конфигурация применяется к типу сущности соединения. Это действие можно выполнить с помощью UsingEntity .
Начальные данные модели можно предоставить для типа сущности соединения с помощью анонимных типов. Вы можете изучить представление отладки модели, чтобы определить имена свойств, созданные по соглашению.
Дополнительные данные можно хранить в типе сущности соединения, но для этого лучше создать тип CLR. При настройке связи с пользовательским типом сущности соединения необходимо явно указать оба внешних ключа.
Конфигурация объединения связей
EF использует две связи "один ко многим" в типе сущности соединения для представления связи "многие ко многим". Эти связи можно настроить в UsingEntity аргументах.
Возможность настройки связей "многие ко многим" появилась в EF Core 5.0 для предыдущей версии используйте следующий подход.
Косвенные связи "многие ко многим"
Можно также представить связь "многие ко многим", просто добавив тип сущности соединения и сопоставив две отдельные связи "один ко многим".
Поддержка формирования шаблонов для связей "многие ко многим" из базы данных еще не добавлена. Отслеживайте решение этого вопроса здесь.
Эта страница содержит сведения о настройке связей в модели с помощью конструктора EF. Общие сведения о связях в EF и о том, как получить доступ к данным и управлять ими с помощью связей, см. в разделе "Свойства навигации связей&".
Связи определяют связи между типами сущностей в модели. В этом разделе показано, как сопоставлять связи с конструктором Entity Framework (конструктор EF). На следующем рисунке показаны основные окна, используемые при работе с конструктором EF.
При построении концептуальной модели в окне Список ошибок могут появиться предупреждения о несопоставленных сущностях и ассоциациях. Эти предупреждения можно игнорировать, так как после создания базы данных из модели ошибки будут удалены.
Одно свойство навигации
Если у вас есть только одно свойство навигации, то существуют перегрузки WithOne без параметров и WithMany . Это означает, что существует концептуальная ссылка или коллекция в другом конце связи, но в классе сущностей нет свойства навигации.
Ограничения
При наличии нескольких свойств навигации, определенных между двумя типами (т. е. несколькими парами навигаций, которые указывают друг на друга), связи, представленные свойствами навигации, являются неоднозначными. Вам потребуется вручную настроить их для разрешения неоднозначности.
Одно свойство навигации
Включение только одного свойства навигации (без обратной навигации и отсутствие свойства внешнего ключа) достаточно для того, чтобы иметь связь, определенную соглашением. Вы также можете иметь одно свойство навигации и свойство внешнего ключа.
Определение терминов
Существует ряд терминов, используемых для описания связей
Зависимый объект: Это сущность, содержащая свойства внешнего ключа. Иногда называют "дочерним" отношения.
Сущность субъекта: Это сущность, содержащая свойства первичного или альтернативного ключа. Иногда называют "родительским" отношением.
Ключ субъекта: Свойства, однозначно определяющие сущность субъекта. Это может быть первичный ключ или альтернативный ключ.
Внешний ключ: Свойства в зависимой сущности, которые используются для хранения значений основного ключа для связанной сущности.
Свойство навигации: Свойство, определенное для основной и (или) зависимой сущности, ссылающейся на связанную сущность.
Свойство навигации коллекции: Свойство навигации, содержащее ссылки на многие связанные сущности.
Эталонное свойство навигации: Свойство навигации, которое содержит ссылку на одну связанную сущность.
Свойство обратной навигации: При обсуждении определенного свойства навигации этот термин относится к свойству навигации в другом конце связи.
Связь с самонаправляющимися объектами: Связь, в которой зависимые и основные типы сущностей совпадают.
В следующем коде показана связь "один ко многим" между Blog и Post
Post является зависимой сущностью
Blog является основной сущностью
Blog.BlogId — это основной ключ (в данном случае это первичный ключ, а не альтернативный ключ).
Post.BlogId является внешним ключом
Post.Blog является ссылочным свойством навигации
Blog.Posts — это свойство навигации по коллекции
Post.Blog — это обратное свойство навигации Blog.Posts (и наоборот)
Configuring navigation properties
This feature was introduced in EF Core 5.0.
After the navigation property has been created, you may need to further configure it.
This call cannot be used to create a navigation property. It is only used to configure a navigation property which has been previously created by defining a relationship or from a convention.
Настройка свойств навигации
Эта возможность появилась в EF Core 5.0.
После создания свойства навигации может потребоваться дополнительно настроить его.
Этот вызов нельзя использовать для создания свойства навигации. Он используется только для настройки свойства навигации, созданного ранее путем определения связи или соглашения.
Удаление ассоциации
Чтобы удалить связь, выполните одно из следующих действий:
Щелкните правой кнопкой мыши связь в области конструктора EF и выберите пункт "Удалить".
Выберите одну или несколько ассоциаций и нажмите клавишу DELETE.
Читайте также: