Способы сопоставления базы данных с Entity Framework?

#c# #.net #database #entity-framework #orm

#c# #.net #База данных #entity-framework #orm

Вопрос:

Сколько существует способов сопоставления базы данных с Entity Framework в .NET?

Я понимаю, что есть code-first и database-first ( .EDMX например, с помощью мастера).

В контексте базы данных -во-первых, могу ли я сопоставить свои таблицы и связи вручную без использования .EDMX ? Сколько существует способов и какие вы рекомендуете?

Существуют ли библиотеки для сопоставления таблиц вручную, какие из них являются лучшими?

Ответ №1:

Я думаю, что это не лучший способ, но, возможно, есть способ, который наилучшим образом соответствует вашим потребностям. Я попытаюсь объяснить, какие у вас есть способы, чем вы можете выбрать лучший для вас.

На высоком уровне есть два варианта:

  • Сначала вы определяете базу данных и предоставляете инструмент для создания ваших классов моделей
  • Сначала код: вы определяете свои классы и позволяете EF управлять таблицами за вас

В основном DB first лучше всего подходит для:

  • Сопоставьте уже существующую базу данных: в этой ситуации ваша БД уже разработана, поэтому вам остается только сопоставить объекты
  • Ваше внимание сосредоточено на структуре БД: в этой ситуации лучше, если вы создадите свою БД так, как хотите, а затем предоставите инструмент для сопоставления ваших сущностей

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

Комментарии:

1. Привет!! Если моя база данных уже создана, существует ли стандарт для сопоставления таблиц и связей? или есть другие способы сделать это?

2. Я никогда не использовал DB сначала с. NET core, но здесь вы можете найти некоторые подсказки: entityframeworktutorial.net/efcore /…

Ответ №2:

Привет, да, можно абсолютно сопоставить базу данных с EF. Он вызывается scaffolding . Что он делает, так это создает базу данных в виде моделей и необходимых файлов для вас.

Как только вы откроете управление пакетами или cmd, вы можете ввести следующую однострочную строку для scafford для вашей базы данных:

CMD:

 dotnet ef dbcontext scaffold "Data Source=(localdb)MSSQLLocalDB;Initial Catalog=Chinook" Microsoft.EntityFrameworkCore.SqlServer
 

Менеджер пакетов:

  Scaffold-DbContext "Data Source=(localdb)MSSQLLocalDB;Initial Catalog=Chinook" Microsoft.EntityFrameworkCore.SqlServer 
 

Смотрите Учебное пособие по EF Core на официальном веб-сайте Windows:

https://docs.microsoft.com/en-us/ef/core/managing-schemas/scaffolding?tabs=dotnet-core-cli

А для EF6 есть отличный учебник прямо здесь:

https://www.illucit.com/en/asp-net/entity-framework-7-code-first-migrations/

Комментарии:

1. Привет!! применимо ли это к стандартному .net?

2. Да, это работает в EF7: illucit.com/en/asp-net/entity-framework-7-code-first-migrations

3. EF7 — это старое название того, что стало ядром EF. В EF6 этот сценарий называется «Сначала закодируйте существующую базу данных» docs.microsoft.com/en-us/ef/ef6/modeling/code-first/workflows /… и EF Core 3.1 поддерживает .NET Framework docs.microsoft.com/en-us/ef/core/miscellaneous/platforms

Ответ №3:

Для полного ручного управления проектом, ориентированным на базу данных, вы можете использовать комбинацию соглашений, атрибутов и / или конфигураций сущностей для настройки сущностей. Я нахожу, что строительные леса работают в 90% случаев, но обычно будет какой-то аспект производственной схемы, особенно там, где у вас нет гибкости для изменения схемы, чтобы сделать ее более удобной для ORM, с которой строительные леса не справляются.

Кроме того, если вы используете что-то вроде ограниченных контекстов (например, DbContexts с сопоставлениями по назначению) и хотите настроить, как таблицы / представления сопоставляются с объектами, тогда это помогает быть более четким с отображением. Например, для общих объектов я буду сопоставлять свойства навигации, но в тех случаях, когда мне нужна необработанная производительность при больших операциях, я захочу отказаться от объявления свойств навигации и работать строго со столбцами FK. Чем меньше «сопоставлений» DbContext приходится беспокоиться и чем меньше объектов он отслеживает, тем быстрее он работает.

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

Т.е.

 [Table("tblOrders", "App")] // tblOrders table in App namespace
public class Order
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int OrderId { get; set; }
    [Column("OrderNum")]
    public string OrderNumber { get; set; }
    public string OrderRef { get; set; }


    [ForeignKey("Customer")]
    public int CustomerId { get; set; }
    public virtual Customer Customer { get; set; }
}
 

Это работает для 90% случаев, когда вы хотите настроить объекты. Для простых столбцов, которые вам не нужно переименовывать и т. Д. вам не нужно добавлять атрибуты и оставлять это в соответствии с соглашением.

Конфигурация сущности: обычно упоминаемый способ сделать это — использовать переопределение OnModelCreating в DbContext и использовать modelBuilder для настройки сущностей. Для небольшой системы с несколькими наборами объектов это может быть управляемо, но для более крупных систем это может стать довольно раздутым, поскольку все заканчивается одним методом или цепочкой вызовов методов для его разделения.

 protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity<Order>()
        .ToTable("tblOrders", "App")
        .HasKey(x => x.OrderId)
        .Property(x => x.OrderId)
            .HasDatabaseGenerated(DatabaseGeneratedOption.Identity);

    modelBuilder.Entity<Order>()
        .Property(x => x.OrderNumber)
            .HasColumnName("OrderNum);

    modelBuilder.Entity<Order>()
        .HasRequired(x => x.Customer)
        .WithMany(x => x.Orders)
        .HasForeignKey(x => x.CustomerId);
   
}
 

Менее документированный вариант — использовать EntityTypeConfigration<TEntity> ( IEntityTypeConfiguration<TEntity> в ядре EF)

 public class OrderConfiguration : EntityTypeConfiguration<Order>
{
    public OrderConfiguration()
    {
        ToTable("tblOrders", "App");
        HasKey(x => x.OrderId)
            .Property(x => x.OrderId)
            .HasDatabaseGenerated(DatabaseGeneratedOption.Identity);

        Property(x => x.OrderNumber)
            .HasColumnName("OrderNum");

        HasRequired(x => x.Customer)
            .WithMany(x => x.Orders)
            .HasForeignKey(x => x.CustomerId);
    }
}
       
 

Оттуда DbContext просто необходимо инициализировать для загрузки конфигураций типов сущностей. Это делается в OnModelCreating, который вы можете выполнить явно или добавить все конфигурации по сборке.

 modelBuilder.Configurations.AddFromAssembly(GetType().Assembly);
 

Лично я по умолчанию объявляю EntityTypeConfigurations для всех объектов, поскольку предпочитаю как можно меньше полагаться на соглашение. Явное указание конфигурации означает, что вам есть что исследовать и с чем работать, когда соглашение работает не так, как вы ожидаете, и это позволяет вам объявлять сопоставления для таких вещей, как ForeignKeys, без объявления свойств FK в сущностях. (Настоятельно рекомендуется избегать двух источников правды об отношениях, являющихся FK и свойством навигации)

Мои проекты обычно будут иметь .Проект данных, в котором я буду хранить сущности, DbContext и репозитории для проекта. Экземпляры EntityTypeConfiguration я размещаю в /Entities/Configuration . Они могут быть так же легко размещены в файлах класса сущностей, как и внутренние члены самого класса сущностей, или вложены в класс сущностей. (т.е. с помощью плагина, такого как NestIn)