Новые возможности в EF Core 2.1

Кроме исправления многочисленных ошибок и небольших улучшений функциональности и производительности, EF Core 2.1 содержит ряд новых интересных функций.

Отложенная загрузка

EF Core теперь содержит стандартные блоки, необходимые для создания классов сущностей, которые могут загружать свои свойства навигации по запросу. Мы также разработали новый пакет Microsoft.EntityFrameworkCore.Proxies, который использует эти стандартные блоки для создания прокси-классов отложенной загрузки на основе минимально измененных классов сущностей (например, классов с виртуальными свойствами навигации).

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

Параметры в конструкторах сущностей

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

Дополнительные сведения об этом см. в разделе, посвященном конструкторам сущностей с параметрами.

Преобразования значений

В предыдущих версиях EF Core было возможно сопоставление свойств только тех типов, которые поддерживались в собственном коде основного поставщика базы данных. Значения копировались между столбцами и свойствами без какого-либо преобразования. Начиная с версии EF Core 2.1 возможно преобразование значений, полученных из столбцов, прежде чем они будут применены к свойствам, и наоборот. Мы предлагаем целый ряд преобразований, которые могут при необходимости применяться стандартным способом, а также API явно задаваемой конфигурации, с помощью которого можно регистрировать настраиваемые преобразования между столбцами и свойствами. Варианты применения этой возможности:

  • Хранение перечислений в строковом виде
  • Сопоставление целочисленных значений со знаком с SQL Server
  • Автоматические шифрование и расшифровка значений свойств

Дополнительные сведения об этом см. в разделе, посвященном преобразованиям значений.

Преобразование оператора LINQ GroupBy

В версиях EF Core, предшествовавших версии 2.1, оператор LINQ GroupBy всегда вычислялся в памяти. На данный момент в большинстве типовых случаев поддерживается его преобразование в предложение SQL GROUP BY.

В этом примере показан запрос с оператором GroupBy, используемый для вычисления различных агрегатных функций:

var query = context.Orders
    .GroupBy(o => new { o.CustomerId, o.EmployeeId })
    .Select(g => new
        {
          g.Key.CustomerId,
          g.Key.EmployeeId,
          Sum = g.Sum(o => o.Amount),
          Min = g.Min(o => o.Amount),
          Max = g.Max(o => o.Amount),
          Avg = g.Average(o => o.Amount)
        });

Соответствующее преобразование в SQL будет иметь следующий вид:

SELECT [o].[CustomerId], [o].[EmployeeId],
    SUM([o].[Amount]), MIN([o].[Amount]), MAX([o].[Amount]), AVG([o].[Amount])
FROM [Orders] AS [o]
GROUP BY [o].[CustomerId], [o].[EmployeeId];

Присвоение начальных значений данных

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

Например, чтобы настроить начальные значения данных для отправки в OnModelCreating, можно использовать следующее:

modelBuilder.Entity<Post>().HasData(new Post{ Id = 1, Text = "Hello World!" });

Дополнительные сведения об этом см. в разделе, посвященном присвоению начальных значений данных.

Типы запросов

Модель EF Core теперь может включать типы запросов. В отличие от типов сущностей типы запросов не имеют определенных ключей и не могут вставляться, удаляться или обновляться (то есть доступны только для чтения), однако при этом они могут напрямую возвращаться запросами. Ниже приведены некоторые сценарии использования типов запросов:

  • Сопоставление с представлениями без первичных ключей
  • Сопоставление с таблицами без первичных ключей
  • Сопоставление с запросами, определенными в модели
  • Использование в качестве типа возвращаемого значения для запросов FromSql()

Дополнительные сведения об этом см. в разделе, посвященном типам запросов.

Использование метода Include с производными типами

В новой версии при написании выражений для метода Include можно будет указывать только свойства навигации, определенные для производных типов. Для строго типизированной версии метода Include будет поддерживаться либо явное приведение, либо оператор as. Кроме того, теперь поддерживается использование ссылок на имена свойств навигации, определенных для производных типов в строковой версии метода Include:

var option1 = context.People.Include(p => ((Student)p).School);
var option2 = context.People.Include(p => (p as Student).School);
var option3 = context.People.Include("School");

Дополнительные сведения об этом см. в разделе, посвященном использованию метода Include с производными типами.

Поддержка System.Transactions

Мы реализовали возможность работы с функциями System.Transactions, такими как TransactionScope. Это будет возможно на платформах .NET Framework и .NET Core при использовании поставщиков баз данных, обеспечивающих соответствующую поддержку.

Дополнительные сведения об этом см. в разделе, посвященном работе с System.Transactions.

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

На основе отзывов клиентов мы обновили функции миграции таким образом, чтобы изначально столбцы таблиц создавались в том порядке, в котором свойства объявлены в классе. Обратите внимание, что EF Core не позволяет изменять порядок при добавлении новых элементов после создания первоначальной таблицы.

Оптимизация коррелированных вложенных запросов

Мы оптимизировали систему преобразования запросов таким образом, чтобы исключить выполнение SQL-запросов "N+1" в большинстве типовых сценариев, в которых использование свойства навигации в проекции приводит к объединению данных из корневого запроса с данными коррелированного вложенного запроса. Для оптимизации применяется буферизация результатов из вложенного запроса. Чтобы явно согласиться на использование нового поведения, необходимо соответствующим образом изменить запрос.

Например, следующий запрос обычно преобразуется в один запрос к Customers и N (где N соответствует возвращаемому числу клиентов) отдельных запросов к Orders:

var query = context.Customers.Select(
    c => c.Orders.Where(o => o.Amount  > 100).Select(o => o.Amount));

Включив в нужном месте ToList(), вы указываете на необходимость буферизации для Orders, что позволяет обеспечить оптимизацию:

var query = context.Customers.Select(
    c => c.Orders.Where(o => o.Amount  > 100).Select(o => o.Amount).ToList());

Обратите внимание, что этот запрос будет преобразован всего в два SQL-запроса: один к Customers и еще один к Orders.

Атрибут [Owned]

В новой версии можно настраивать собственные типы сущностей, просто аннотируя тип с использованием [Owned] с последующей проверкой того, что сущность владельца добавлена в модель:

[Owned]
public class StreetAddress
{
    public string Street { get; set; }
    public string City { get; set; }
}

public class Order
{
    public int Id { get; set; }
    public StreetAddress ShippingAddress { get; set; }
}

Программа командной строки dotnet-ef, входящая в пакет SDK для .NET Core

Теперь команды dotnet-ef входят в пакет SDK для .NET Core, поэтому необязательно использовать DotNetCliToolReference в проекте, чтобы выполнять перенос или формировать DbContext из существующей базы данных.

Дополнительные сведения о включении программ командной строки для разных версий пакета SDK для .NET Core и EF Core см. в разделе об установке средств.

Пакет Microsoft.EntityFrameworkCore.Abstractions

Новый пакет содержит атрибуты и интерфейсы, которые можно использовать в проектах для улучшения функций EF Core без необходимости создавать зависимости от Core EF. Например, здесь находится атрибут [Owned] и интерфейс ILazyLoader.

События изменения состояния

Новые события Tracked и StateChanged в ChangeTracker можно использовать для записи логики, которая реагирует на ввод сущностей DbContext или изменение их состояния.

Анализатор необработанных параметров SQL

Новый анализатор кода входит в состав EF Core для обнаружения потенциально небезопасных случаев использования необработанных API SQL, например FromSql или ExecuteSqlCommand. Например, в следующем запросе будет отображено предупреждение, так как для minAge параметры отсутствуют:

var sql = $"SELECT * FROM People WHERE Age > {minAge}";
var query = context.People.FromSql(sql);

Совместимость с поставщиками баз данных

Рекомендуется использовать EF Core 2.1 с поставщиками, которые были обновлены и по меньшей мере протестированы для работы с EF Core 2.1.

Совет

Если вы столкнулись с неожиданными проблемами с совместимостью или другими ошибками в новых возможностях, сообщите нам об этом с помощью средства отслеживания проблем.