Posted on 18. March 2020

Анонс Entity Framework Core 5.0 Preview 1

Сегодня Microsoft объявили о первом пред просмотре EF Core 5.0.

Предпосылки

Для предварительного просмотра EF Core 5.0 требуется .NET Standard 2.1. Это означает:

• EF Core 5.0 работает на .NET Core 3.1; это не требует .NET 5.

○ Это может измениться в будущих превью в зависимости от того, как будет развиваться план для .NET 5.

EF Core 5.0 работает на других платформах, поддерживающих .NET Standard 2.1.

EF Core 5.0 не будет работать на платформах .NET Standard 2.0, включая .NET Framework.

Как скачать EF Core 5.0?

EF Core распространяется исключительно как набор пакетов NuGet. Например, чтобы добавить поставщика SQL Server в свой проект, вы можете использовать следующую команду с помощью инструмента dotnet:

dotnet add package Microsoft.EntityFrameworkCore.SqlServer --version 5.0.0-preview.2.20120.8

 

Пакеты EF Core, опубликованные сегодня:

Microsoft.EntityFrameworkCore - основной пакет EF Core

Microsoft.EntityFrameworkCore.SqlServer - поставщик базы данных для Microsoft SQL Server и SQL Azure

Microsoft.EntityFrameworkCore.Sqlite - поставщик базы данных для SQLite

Microsoft.EntityFrameworkCore.Cosmos - поставщик базы данных для Azure Cosmos DB

Microsoft.EntityFrameworkCore.InMemory - поставщик базы данных в памяти

Microsoft.EntityFrameworkCore.Tools - команды EF Core PowerShell для консоли диспетчера пакетов Visual Studio

Microsoft.EntityFrameworkCore.Design - общие компоненты времени разработки для инструментов EF Core

Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite - поддержка SQL Server для пространственных типов

Microsoft.EntityFrameworkCore.Sqlite.NetTopologySuite - поддержка SQLite для пространственных типов

Microsoft.EntityFrameworkCore.Proxies - загрузка и отслеживание изменений прокси

Microsoft.EntityFrameworkCore.Abstractions - разделенные EF Core абстракции

Microsoft.EntityFrameworkCore.Relational - общие компоненты EF Core для поставщиков реляционных баз данных

Microsoft.EntityFrameworkCore.Analyzers - анализаторы C # для EF Core

Microsoft.EntityFrameworkCore.Sqlite.Core - поставщик базы данных для SQLite без упакованного собственного двоичного файла

Мы также опубликовали версию 5.0 Preview 1 от  поставщика ADO.NET Microsoft.Data.Sqlite.Core.

Установка dotnet ef

Как и в случае EF Core 3.0 и 3.1, инструмент командной строки dotnet ef больше не включается в .NET Core SDK. Прежде чем вы сможете выполнить команды переноса EF Core или создания лесов, вам необходимо установить этот пакет как глобальный или локальный инструмент.

Чтобы установить инструмент предварительного просмотра глобально, сначала удалите любую существующую версию с помощью:

dotnet tool uninstall --global dotnet-ef

 

Затем установите с помощью:

dotnet tool install --global dotnet-ef --version 5.0.0-preview.2.20120.8

Эту новую версию dotnet ef можно использовать с проектами, в которых используются более старые версии среды выполнения EF Core.

Номера версий пакетов

В процессе сборки .NET 5 произошла ошибка, в результате которой пакеты EF preview 1 были ошибочно помечены как «5.0.0-preview.2.20120.8».

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

Что нового в EF Core 5 Preview 1

Мы поддерживаем документацию новых функциях, представленных в каждом предварительном просмотре.

Некоторые из основных моментов из предварительного просмотра 1 вызываются ниже.

Простая регистрация

Эта опция функционально похожа на Database.Log в EF6. Таким образом, он предоставляет простой способ получения журналов из EF Core без необходимости настройки какого-либо внешнего каркаса ведения журналов.

EF Core заменяет Database.Log методом LogTo, вызываемым для DbContextOptionsBuilder в AddDbContext или OnConfiguring. Например:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.LogTo(Console.WriteLine);

 

Существуют перегрузки для:

• Установите минимальный уровень журнала

Пример: .LogTo(Console.WriteLine, LogLevel.Information)

• Фильтр только для определенных событий

Пример: .LogTo(Console.WriteLine, new[] {CoreEventId.ContextInitialized, RelationalEventId.CommandExecuted})

• Фильтр для всех событий в определенных категориях:

Пример: .LogTo(Console.WriteLine, new[] {DbLoggerCategory.Database.Name}, LogLevel.Information)

• Используйте пользовательский фильтр по событию и уровню:

Пример: .LogTo(Console.WriteLine, (id, level) => id == RelationalEventId.CommandExecuting)

 

Формат вывода может быть минимально сконфигурирован (API постоянно меняется), но вывод по умолчанию выглядит примерно так:

warn: 12/5/2019 09:57:47.574 CoreEventId.SensitiveDataLoggingEnabledWarning[10400] (Microsoft.EntityFrameworkCore.Infrastructure)
      Sensitive data logging is enabled. Log entries and exception messages may include sensitive application data, this mode should only be enabled during development.
dbug: 12/5/2019 09:57:47.581 CoreEventId.ShadowPropertyCreated[10600] (Microsoft.EntityFrameworkCore.Model.Validation)
      The property 'BlogId' on entity type 'Post' was created in shadow state because there are no eligible CLR members with a matching name.
info: 12/5/2019 09:57:47.618 CoreEventId.ContextInitialized[10403] (Microsoft.EntityFrameworkCore.Infrastructure)
      Entity Framework Core 5.0.0-dev initialized 'BloggingContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer' with options: SensitiveDataLoggingEnabled
dbug: 12/5/2019 09:57:47.644 CoreEventId.ValueGenerated[10808] (Microsoft.EntityFrameworkCore.ChangeTracking)
      'BloggingContext' generated temporary value '-2147482647' for the 'Id' property of new 'Blog' entity.
...

 

Простой способ получить сгенерированный SQL

В EF Core 5.0 представлен метод расширения ToQueryString, который будет возвращать SQL, который EF Core сгенерирует при выполнении запроса LINQ. Например, код:

var query = context.Set<customer>().Where(c => c.City == city);
Console.WriteLine(query.ToQueryString())

приводит к таким выводам при использовании поставщика базы данных SQL Server:

DECLARE p0 nvarchar(4000) = N'London';
 
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
WHERE [c].[City] = @__city_0

 

Обратите внимание, что объявления для параметров правильного типа также включены в вывод. Это позволяет копировать / вставлять в SQL Server Management Studio или аналогичные инструменты, так что запрос может быть выполнен для отладки / анализа.

Используйте атрибут C #, чтобы указать, что у объекта нет ключа

Тип объекта теперь можно настроить как “не имеющий ключа”, используя новый KeylessAttribute. Например:

[Keyless]
public class Address
{
    public string Street { get; set; }
    public string City { get; set; }
    public int Zip { get; set; }
}

 

Соединение или строка соединения могут быть изменены при инициализации DbContext

Теперь проще создать экземпляр DbContext без какого-либо соединения или строки соединения. Кроме того, соединение или строка соединения теперь могут быть изменены в экземпляре контекста. Это позволяет одному и тому же экземпляру контекста динамически подключаться к разным базам данных.

Прокси отслеживания изменений

EF Core теперь может генерировать прокси во время выполнения, которые автоматически реализуют INotifyPropertyChanging и  INotifyPropertyChanged. Затем они сообщают об изменениях значений свойств сущностей непосредственно в EF Core, избегая необходимости сканировать изменения. Однако прокси-серверы имеют свои собственные ограничения, поэтому они не для всех.

Расширенные представления отладки

Представления отладки - это простой способ взглянуть на внутренности EF Core при отладке проблем. Представление отладки для Модели было реализовано. Для EF Core 5.0 мы упростили представление модели и добавили новое представление отладки для отслеживаемых объектов в диспетчере состояний.

Модель отладки

Разверните свойство Model объекта DbContext в выбранном отладчике и раскройте свойство DebugView.


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

Model:

  EntityType: Chassis

    Properties:

      TeamId (int) Required PK FK AfterSave:Throw

      Name (string)

      Version (no field, byte[]) Shadow Concurrency BeforeSave:Ignore AfterSave:Ignore ValueGenerated.OnAddOrUpdate

    Navigations:

      Team (_team, Team) ToPrincipal Team Inverse: Chassis PropertyAccessMode.Field

    Keys:

      TeamId PK

    Foreign keys:

      Chassis {'TeamId'} -> Team {'Id'} Unique ToDependent: Chassis ToPrincipal: Team

  EntityType: Driver

    Properties:

      Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd

      CarNumber (Nullable<int>)

      Championships (int) Required

      Discriminator (no field, string) Shadow Required

      FastestLaps (int) Required

      Name (string)

      Podiums (int) Required

      Poles (int) Required

      Races (int) Required

      TeamId (int) Required FK Index

      Version (no field, byte[]) Shadow Concurrency BeforeSave:Ignore AfterSave:Ignore ValueGenerated.OnAddOrUpdate

      Wins (int) Required

    Navigations:

      Team (_team, Team) ToPrincipal Team Inverse: Drivers PropertyAccessMode.Field

    Keys:

      Id PK

    Foreign keys:

      Driver {'TeamId'} -> Team {'Id'} ToDependent: Drivers ToPrincipal: Team

    Indexes:

      TeamId

  EntityType: Engine

    Properties:

      Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd

      EngineSupplierId (int) Required FK Index Concurrency

      Name (string) Concurrency

    Navigations:

      EngineSupplier (_engineSupplier, EngineSupplier) ToPrincipal EngineSupplier Inverse: Engines PropertyAccessMode.Field

      Gearboxes (_gearboxes, ICollection<gearbox>) Collection ToDependent Gearbox PropertyAccessMode.Field

      StorageLocation (Location) ToDependent Location PropertyAccessMode.Field

      Teams (_teams, ICollection<team>) Collection ToDependent Team Inverse: Engine PropertyAccessMode.Field

    Keys:

      Id PK

    Foreign keys:

      Engine {'EngineSupplierId'} -> EngineSupplier {'Id'} ToDependent: Engines ToPrincipal: EngineSupplier

    Indexes:

      EngineSupplierId

  EntityType: EngineSupplier

    Properties:

      Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd

      Name (string)

    Navigations:

      Engines (_engines, ICollection<engine>) Collection ToDependent Engine Inverse: EngineSupplier PropertyAccessMode.Field

    Keys:

      Id PK

  EntityType: Gearbox

    Properties:

      Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd

      EngineId (no field, Nullable<int>) Shadow FK Index

      Name (string)

    Keys:

      Id PK

    Foreign keys:

      Gearbox {'EngineId'} -> Engine {'Id'} ToDependent: Gearboxes

    Indexes:

      EngineId

  EntityType: Location

    Properties:

      EngineId (no field, int) Shadow Required PK FK AfterSave:Throw ValueGenerated.OnAdd

      Latitude (double) Required Concurrency

      Longitude (double) Required Concurrency

    Keys:

      EngineId PK

    Foreign keys:

      Location {'EngineId'} -> Engine {'Id'} Unique Ownership ToDependent: StorageLocation

  EntityType: Sponsor

    Properties:

      Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd

      ClientToken (no field, Nullable</int><int>) Shadow Concurrency

      Discriminator (no field, string) Shadow Required

      Name (string)

      Version (no field, byte[]) Shadow Concurrency BeforeSave:Ignore AfterSave:Ignore ValueGenerated.OnAddOrUpdate

    Keys:

      Id PK

  EntityType: SponsorDetails

    Properties:

      TitleSponsorId (no field, int) Shadow Required PK FK AfterSave:Throw ValueGenerated.OnAdd

      ClientToken (no field, Nullable</int><int>) Shadow Concurrency

      Days (int) Required

      Space (decimal) Required

      Version (no field, byte[]) Shadow Concurrency BeforeSave:Ignore AfterSave:Ignore ValueGenerated.OnAddOrUpdate

    Keys:

      TitleSponsorId PK

    Foreign keys:

      SponsorDetails {'TitleSponsorId'} -> TitleSponsor {'Id'} Unique Ownership ToDependent: Details

  EntityType: Team

    Properties:

      Id (int) Required PK AfterSave:Throw

      Constructor (string)

      ConstructorsChampionships (int) Required

      DriversChampionships (int) Required

      EngineId (no field, Nullable</int><int>) Shadow FK Index

      FastestLaps (int) Required

      GearboxId (Nullable</int><int>) FK Index

      Name (string)

      Poles (int) Required

      Principal (string)

      Races (int) Required

      Tire (string)

      Version (no field, byte[]) Shadow Concurrency BeforeSave:Ignore AfterSave:Ignore ValueGenerated.OnAddOrUpdate

      Victories (int) Required

    Navigations:

      Chassis (_chassis, Chassis) ToDependent Chassis Inverse: Team PropertyAccessMode.Field

      Drivers (_drivers, ICollection<driver>) Collection ToDependent Driver Inverse: Team PropertyAccessMode.Field

      Engine (_engine, Engine) ToPrincipal Engine Inverse: Teams PropertyAccessMode.Field

      Gearbox (_gearbox, Gearbox) ToPrincipal Gearbox PropertyAccessMode.Field

    Keys:

      Id PK

    Foreign keys:

      Team {'EngineId'} -> Engine {'Id'} ToDependent: Teams ToPrincipal: Engine

      Team {'GearboxId'} -> Gearbox {'Id'} Unique ToPrincipal: Gearbox

    Indexes:

      EngineId

      GearboxId Unique

  EntityType: TestDriver Base: Driver

  EntityType: TitleSponsor Base: Sponsor

    Navigations:

      Details (_details, SponsorDetails) ToDependent SponsorDetails PropertyAccessMode.Field

 

Менеджер “debug view”

Состояние менеджера немного скрыто, чем модель. Чтобы найти его, перейдите в свойство ChangeTracker объекта DbContext в выбранном вами отладчике, а затем посмотрите в свойстве StateManager  и разверните DebugView.

Краткий обзор менеджера отображает:

• Каждый объект отслеживается

• Значение первичного ключа

• Состояние объекта: добавлено, не изменено, изменено или удалено.

• Значения свойства внешнего ключа

Например:

Engine (Shared) {Id: 1} Unchanged FK {EngineSupplierId: 1}
Location (Shared) {EngineId: 1} Unchanged FK {EngineId: 1}
Team (Shared) {Id: 4} Modified FK {EngineId: 1} FK {GearboxId: <null>}

 

Длинный вид показывает все в коротком виде:

• Текущее значение каждого свойства

• Независимо от того, помечено ли свойство как измененное

• Исходное значение свойства, если оно отличается от текущего значения

• Сущность, на которую ссылается ссылочная навигация с использованием значения первичного ключа ссылочной сущности

• Список объектов, на которые ссылается навигация по коллекции, снова используя значения первичного ключа

Например:

Engine (Shared) {Id: 1} Unchanged
  Id: 1 PK
  EngineSupplierId: 1 FK
  Name: 'FO 108X'
  EngineSupplier: <null>
  Gearboxes: </null><null>
  StorageLocation: {EngineId: 1}
  Teams: [{Id: 4}]
Location (Shared) {EngineId: 1} Unchanged
  EngineId: 1 PK FK
  Latitude: 47.64491
  Longitude: -122.128101
Team (Shared) {Id: 4} Modified
  Id: 4 PK
  Constructor: 'Ferrari'
  ConstructorsChampionships: 16
  DriversChampionships: 15
  EngineId: 1 FK Modified Originally 3
  FastestLaps: 221
  GearboxId: </null><null> FK
  Name: 'Scuderia Ferrari Marlboro'
  Poles: 203
  Principal: 'Stefano Domenicali'
  Races: 805
  Tire: 'Bridgestone'
  Version: '0x000000000001405A'
  Victories: 212
  Chassis: </null><null>
  Drivers: []
  Engine: {Id: 1}
  Gearbox: </null><null>

 

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

Реляционные базы данных обычно обрабатывают NULL как неизвестное значение и, следовательно, не равны никаким другим NULL. C #, с другой стороны, рассматривает нулл как определенное значение, которое сравнивается с любым другим нулл. EF Core по умолчанию переводит запросы так, чтобы они использовали нулевую семантику C #. EF Core 5.0 значительно повышает эффективность этих переводов.

Свойства индексатора

EF Core 5.0 поддерживает отображение свойств индексатора C #. Это позволяет подразделениям действовать как пакеты свойств, в которых столбцы сопоставляются с именованными свойствами в пакете.

Генерация проверочных ограничений для отображений enum

Миграции EF Core 5.0 теперь могут генерировать ограничения CHECK для сопоставлений свойств перечисления. Например:

EnumColumn VARCHAR(10) NOT NULL CHECK (MyEnumColumn IN('Useful', 'Useless', 'Unknown'))

 

IsRelational

Новый метод IsRelational был добавлен в дополнение к существующим IsSqlServerIsSqlite и IsInMemory.

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

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    if (Database.IsRelational())
    {
        // Do relational-specific model configuration.
    }
}

 

Советующая поддержка  Cosmos с ETags

Поставщик базы данных Azure Cosmos DB теперь поддерживает ETags. Используйте конструктор моделей в OnModelCreating для настройки ETag:

builder.Entity&lt;customer>().Property(c => c.ETag).IsEtagConcurrency();

 

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

Как запросить переводы для большего количества конструкций DateTime?

Запросы, содержащие новую конструкцию DateTime, теперь переведены.

Кроме того, теперь сопоставлены следующие функции SQL Server: * DateDiffWeek * DateFromParts

Например:

var count = context.Orders.Count(c => date > EF.Functions.DateFromParts(DateTime.Now.Year, 12, 25));

 

Перевод запросов для большего количества массива байтов

Запросы, использующие свойства Contains, Length, SequenceEqual и т. Д. В byte [], теперь переводятся в SQL. Например:

var blogs = context.Blogs.Where(e => e.Picture.Contains((byte)127)).ToList();

 

Перевод запроса для реверса

Запросы с использованием Reverse теперь переведены. Например:

context.Employees.OrderBy(e => e.EmployeeID).Reverse()

 

Запрос для битовых операторов

Запросы с использованием битовых операторов теперь транслируются в большем количестве случаев. Например:

context.Orders.Where(o => ~o.OrderID == negatedId)

 

Перевод запроса на строки в Cosmos

Запросы, использующие строковые методы Contains, StartsWith и EndsWith, теперь переводятся при использовании поставщика Azure Cosmos DB.

Ежедневные сборки

Предварительные просмотры EF Core соответствуют предварительным просмотрам .NET 5. Эти превью имеют тенденцию отставать от последней работы над EF Core. Вместо этого рассмотрите возможность использования ежедневных сборок, чтобы получить самые современные функции EF Core и исправления ошибок.

Как и в случае предварительного просмотра, для ежедневных сборок не требуется .NET 5; их можно использовать с GA / RTM-версией .NET Core 3.1.

Документация и отзывы

Отправной точкой для всей документации EF Core является docs.microsoft.com/ef/core/.

Пожалуйста, сообщайте о найденных проблемах и любые другие отзывы dotnet/efcore GitHub repo.

Источник