Ваш код является очень приемлемым и должен хорошо служить вам, но давайте рассмотрим, почему существует сочетание Attributes и Fluent API.
У конвейера EF есть три основных момента, куда мы можем внедрять метаданные базы данных. (конфигурация таблицы), к ним относятся:
- Обозначение атрибута
- Условные обозначения первого кода
- API конфигурации Fluent
Порядок выше спискатакже показывает порядок их обработки в конвейере, внутренне атрибуты не имеют смысла для DbContext, пока они не будут проанализированы встроенными (или настроенными) соглашениями, эти соглашения внутренне используют API-интерфейс Fluent для настройки DbContext.
Различные сценарии требуют и допускают разные миксы, как правило, в нотации атрибутов сценария Code First предпочтительнее интенсивного использования Fluent API. Однако ограничения внешнего ключа, которые включают каскадные удаления или многие-многие отношения, такие как это, часто выражаются непосредственно в Fluent API, поскольку синтаксис может быть немного проще, а также гарантировать, что никакие другие соглашения не могут переопределить нашу ожидаемую реализацию в базе данных.
Нотация атрибутов позволяет в основном содержать схему вашей таблицы в определении класса, но все же позволяет среде выполнения приложения переопределять интерпретации этих атрибутов путем настройки или отключения встроенных соглашений.
Если ваши метаданные могут быть выражены с помощью атрибутов, тогда вся спецификация вашей схемы становится более краткой, что особенно полезно при представлении ваших решений кода в Интернете в примерах, где важно показать структуру и взаимосвязи. Если вашему онлайн-примеру нужно только выразить взаимосвязь, то в этих примерах часто используется только беглая запись. - Пример понятного для реализации кода, если вам нужно выразить и схему, и отображение отношений по отдельности.
Если вы используете нотацию атрибутов, тогда ваш пример может быть выражен так, и вам не понадобится ничего лишнегов OnModelCreating :
public class Project
{
[Key]
public int ProjectId { get; set; }
public string ProjectName { get; set; }
...
public virtual ICollection<ProjectTechnologyLink> ProjectTechnologyLink { get; set; } = new HashSet<ProjectTechnologyLink>();
}
ПРИМЕЧАНИЕ: В приведенном выше определении класса Project
я использовал встроенный инициализатор для отношения ProjectTechnologyLink
,я считаю, что этот стиль хорошо согласуется с нотацией атрибута , так как значение по умолчанию теперь также определяется в непосредственной близости со свойством, когда инициализаторы определяются только в конструкторе, легко забыть включить init вообще или может быть сложно найти логику init в коде. Теперь быстрое «Got To Definition» покажет реализацию по умолчанию, а также любые атрибуты, связанные со схемой базы данных, без необходимости поиска других ресурсов.
public class Technology
{
public Technology()
{
ProjectTechnologyLink = new HashSet<ProjectTechnologyLink>();
}
[Key]
public int TechnologyId { get; set; }
public string TechnologyName { get; set; }
...
public virtual ICollection<ProjectTechnologyLink> ProjectTechnologyLink { get; set; }
}
public class ProjectTechnologyLink
{
[Key, Column(Order = 0)]
public int ProjectId { get; set; }
[Key, Column(Order = 0)]
public int TechnologyId { get; set; }
...
[ForeignKey(nameof(ProjectId))]
public virtual Project Project { get; set; }
[ForeignKey(nameof(TechnologyId))]
public virtual Technology Technology { get; set; }
}
virtual Свойства навигации: В EF важно пометить ваши свойства навигации как виртуальных членов. Это позволит EF реализовать отложенную загрузку и выполнить другую оптимизированную реализацию этих свойств, когда он генерирует класс-оболочку, который наследуется от вашего класса сущностей. Даже если вы не намерены поддерживать Lazy Loading , существуют другие сценарии, в которых EF обернет ваш класс, и в любом случае ваши классы определения данных не должны быть обеспокоены или знать об оперативном решении, которое может быть принято и изменено. во время выполнения в зависимости от ваших потребностей контекста.
Условные обозначения: Предыдущий пример демонстрирует чистую запись атрибутов. Очень возможно заменить стандартные условные обозначения на собственные для определения первичных и внешних ключей. Это означает, что теоретически возможно не иметь никаких атрибутов или беглых обозначений вообще. Я стараюсь не поощрять подход, основанный исключительно на соглашениях, потому что это затрудняет поиск конфигурации в определении большой или распределенной схемы, что также является тем же аргументом, который я использую, чтобы препятствовать подходу чистого Fluent API, атрибуты являются логическим местом длядокументировать ожидаемое использование таблицы или поля.