Сегодня 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)
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) Collection ToDependent Gearbox PropertyAccessMode.Field
StorageLocation (Location) ToDependent Location PropertyAccessMode.Field
Teams (_teams, ICollection) 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) 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) 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, Nullableint><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, Nullableint><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, Nullableint><int>) Shadow FK Index
FastestLaps (int) Required
GearboxId (Nullableint><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) 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: }
Длинный вид показывает все в коротком виде:
• Текущее значение каждого свойства
• Независимо от того, помечено ли свойство как измененное
• Исходное значение свойства, если оно отличается от текущего значения
• Сущность, на которую ссылается ссылочная навигация с использованием значения первичного ключа ссылочной сущности
• Список объектов, на которые ссылается навигация по коллекции, снова используя значения первичного ключа
Например:
Engine (Shared) {Id: 1} Unchanged
Id: 1 PK
EngineSupplierId: 1 FK
Name: 'FO 108X'
EngineSupplier:
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 был добавлен в дополнение к существующим IsSqlServer
, IsSqlite
и 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<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.
Источник