Правильный ли класс модели EF? - PullRequest
2 голосов
/ 07 октября 2019

Сначала я хочу использовать код EF для применения моделирования существующих таблиц базы данных.

Допустим, у меня есть три таблицы.

  1. Project таблица. Первичным ключом является ProjectId, он имеет другие столбцы, такие как ProjectName, StartDate и EndDate и т. Д.
  2. Technology таблица. Первичный ключ - TechnologyId, остальные столбцы - имя_технологии, примечание и т. Д.
  3. ProjectTechnologyLink. Свяжите две таблицы вместе. Он имеет первичный ключ ProjectId и TechnologyId, также они являются внешними ключами.

Примеры данных в ProjectTechnologyLink

ProjectId    TechnologyId    CreatedBy  CreatedDate
25            3               One       2016-01-01
100           4               One       2016-01-01
100           8               Two       2016-01-01

Предположим, что один проект может иметь много технологий, а одна технология может существовать во многих проектах.

Классы моделейявляются: Для проекта:

public class Project
{
    public int ProjectId {get;set;}
    public string ProjectName {get;set;}
    ...
    public ICollection<ProjectTechnologyLink> ProjectTechnologyLink
}

Для технологии:

public class Technology
{ 
    public Technology()
    {
        ProjectTechnologyLink = new HashSet<ProjectTechnologyLink>();
    }
    public int TechnologyId {get;set;}
    public string TechnologyName {get;set;}
    ...
    public ICollection<ProjectTechnologyLink> ProjectTechnologyLink {get;set;}
 }

Для класса ProjectTechnologyLink.

public class ProjectTechnologyLink 
{
    public int ProjectId {get;set;}
    public int TechnologyId {get;set;}
    ...
    public Project Project {get;set;}
    public Technology Technology {get;set;}
}

Затем в методе OnModelCreating.

modelBuilder.Entity<ProjectTechLink>(entity => 
    {
        entity.HasKey(e=> new {e.ProjectId, e.TechnologyId});
        entity.ToTable("ProjectTechnology", "myscheme");
        entity.HasOne(x=>x.Project)
              .WithMany(p=>p.ProjectTechnologyLink)
              .HasForeignKey(d=>d.ProjectId)
              .OnDelete(DeleteBehavior.ClientSetNull)
              .HasConstraintName("FK_PROJECT_TECHNOLOGY_LINK_PID");

       entity.HasOne(x=>x.Technology)
              .WithMany(p=>p.ProjectTechnologyLink)
              .HasForeignKey(d=>d.TechnologyId)
              .OnDelete(DeleteBehavior.ClientSetNull)
              .HasConstraintName("FK_PROJECT_TECHNOLOGY_LINK_TID");
      });

Мой вопрос: правильно ли это для всего кода? Иногда я видел, как люди ставят некоторые атрибуты перед свойствами в классе. Но у меня его нет.

1 Ответ

1 голос
/ 07 октября 2019

Ваш код является очень приемлемым и должен хорошо служить вам, но давайте рассмотрим, почему существует сочетание Attributes и Fluent API.

У конвейера EF есть три основных момента, куда мы можем внедрять метаданные базы данных. (конфигурация таблицы), к ним относятся:

  1. Обозначение атрибута
  2. Условные обозначения первого кода
  3. 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, атрибуты являются логическим местом длядокументировать ожидаемое использование таблицы или поля.

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