4 декабря вышла финальная версия EF Core 2.2. Она выпущена параллельно с ASP.NET Core 2.2 и .NET Core 2.2 и является самым свежим релизом нашей опенсорсной и кроссплатформенной технологии для управления отображениями между объектами языка и базой данных.
EF Core 2.2 RTM содержит больше сотни исправлений и несколько новых фич, о которых мы и поговорим в этой статье.
Ссылки ведут на соответствующие статьи на Хабре. Это последняя, третья статья серии. В следующий раз мы поговорим о новом релизе — и это будет уже в новом году.
Пространственные данные
Пространственные (spatial) данные используются для хранения физического месторасположения и формы объектов. Множество существующих баз данных имеют встроенные способы хранения, индексации и поиска таких данных. Основные сценарии использования заключаются в поиске объектов на выбранной дистанции и проверке, что какой-то из полигонов содержит заданную точку. EF Core 2.2 теперь сможет работать с такими базами и геоданными в них, используя типы из библиотеки NetTopologySuite (NTS).
Пространственные данные реализованы как наборы пакетов расширений для специальных провайдеров. Каждый из таких пакетов добавляет как новые отображения для типов и методов NTS, так и соответствующие им пространственные типы и функции в базе данных. Такие расширения провайдеров уже реализованы для SQL Server, SQLite и PostgreSQL (благодаря проекту Npgsql). Пространственные типы можно использовать напрямую, вместе с in-memory провайдером EF Core, не используя никаких других расширений.
Как только расширение установлено, включается поддержка новых типов. Свойства с этими типами можно использовать в своих сущностях, например:
using NetTopologySuite.Geometries;
namespace MyApp
{
public class Friend
{
[Key]
public string Name { get; set; }
[Required]
public Point Location { get; set; }
}
}
Конечно, теперь эти данные можно сохранять:
using (var context = new MyDbContext())
{
context.Add(
new Friend
{
Name = "Bill",
Location = new Point(-122.34877, 47.6233355) {SRID = 4326 }
});
context.SaveChanges();
}
Аналогично становится возможным делать к базе данных запросы, которые задействуют пространственные данные и операции:
var nearestFriends =
(from f in context.Friends
orderby f.Location.Distance(myLocation) descending
select f).Take(5).ToList();
Пространственные данные — это большая тема, знакомство с которой стоит начать с официальной документации.
Коллекции зависимых сущностей
В EF Core 2.0 появилась возможность моделировать отношения «один к одному». EF Core 2.2 расширяет эту фичу возможностью напрямую указать, кто является в таком отношении основной сущностью (owner), а кто — зависимой (owned). Это позволяет ограничить и уточнить область использования сущности.
Например, зависимые сущности:
- Могут использоваться только в ссылочных свойствах (англ. «navigation property»), содержащихся в других типах сущностей;
- Автоматически загружаются и отслеживаются в
DbContext
только вместе со своей основной сущностью.
В реляционных базах данных зависимые коллекции отображаются не в таблицу основной сущности, а в отдельные таблицы, аналогично обычным отношениям «один ко многим». В документно-ориентированных базах всё несколько иначе, и мы планируем вкладывать зависимые сущности (в зависимых коллекциях или ссылках) в тот же самый документ, в котором хранится основная сущность.
Фичу можно использовать, вызвав новый API OwnsMany()
:
modelBuilder.Entity<Customer>().OwnsMany(c => c.Addresses);
За дополнительными сведениями стоит обратиться к документации.
Метки запросов (Query tags)
Эта фича предназначена для упрощения задачи поиска связи между LINQ-запросами в коде и сгенерированными по ним SQL-запросами, которые можно обнаружить в логах.
Чтобы включить метки, нужно проаннотировать LINQ-запрос с помощью нового метода TagWith()
. Давайте немного модифицируем предыдущий пример из раздела про пространственные данные:
var nearestFriends =
(from f in context.Friends.TagWith(@"This is my spatial query!")
orderby f.Location.Distance(myLocation) descending
select f).Take(5).ToList();
В логе можно будет увидеть следующий текст:
-- This is my spatial query!
SELECT TOP(@__p_1) [f].[Name], [f].[Location]
FROM [Friends] AS [f]
ORDER BY [f].[Location].STDistance(@__myLocation_0) DESC
Как всегда, про это есть [раздел в документации].
Совместимость с EF Core 2.1
Мы потратили много времени и сил, обеспечив обратную совместимость EF Core 2.2 с существующими провайдерами EF Core 2.1 и сделав так, чтобы после обновления на EF Core 2.2 приложение собралось без видимых проблем. Скорее всего, в большинстве случаев миграция на новую версию будет простой, но тем не менее, если вы вдруг встретитесь с проблемами, стоит рассказать о них в нашем багтрекере.
На данный момент существует всего одно изменение, которое может потребовать небольших изменений кода приложения. Прочитать о нем можно в описании следующего тикета:
- #13986: Тип, настроенный одновременно и как обычное свойство, и как зависимое, требует создания первичного ключа сразу после обновления с 2.1 на 2.2.
Мы намереваемся продолжать поддерживать и обновлять список проблем, требующих модификации старого кода.
Что дальше: EF Core 3.0
После выхода версии 2.2 наша следующая цель — EF Core 3.0. Мы ещё не реализовали никаких новых фичей, поэтому вышедшие 4 декабря пакеты NuGet содержат всего лишь несколько небольших изменений, сделанных после выхода EF Core 2.2.
Уже есть несколько широко обсуждаемых больших идей, запланированных на следующий релиз. Мы хотим рассказать о них в следующих выпусках новостей, но вот несколько тем, про которые уже можно кое-что заявить:
-
Улучшения в LINQ. LINQ позволяет писать запросы к базе данных без необходимости переходить из своего основного языка на язык базы данных, используя информацию о типах для отображения IntelliSense и проверки на этапе компиляции. Но это же означает, что LINQ позволяет писать неограниченное количество сложных запросов, которые всегда были настоящим испытанием для LINQ-провайдеров. В первых версиях EF Core мы решили эту проблему тем, что определили, какие части запроса можно транслировать в SQL, и потом разрешили оставшейся части запроса выполняться прямо на клиенте, с использованием памяти этого клиента. Это выполнение на стороне клиента иногда может быть полезно, но во множестве случаев приводит к крайне неэффективным запросам, которые не найти до тех пор, пока код не пойдёт в продакшн. В EF Core 3.0 хочется проделать тщательную работу по изменению внутренностей LINQ и способов их тестирования. Нужно сделать их более прочными и надежными (например, чтобы запросы не ломались после накатывания свежих патч-релизов); реализовать корректную трансляцию в SQL большего числа выражений; сфокусироваться на генерации запросов, которые будут работать более эффективно в большем количестве случаев; подумать над тем, чтобы неэффективные запросы не прошли незамеченными.
-
Поддержка Cosmos DB. Мы продолжаем работать над провайдером Cosmos DB для EF Core для того, чтобы разработчики, знакомые с программной моделью EF, сразу же могли таргетироваться на Azure Cosmos DB в качестве своей основной базы. Задача в том, чтобы задействовать самое лучшее в Cosmos DB, например global distribution, «always on» availability, elastic scalability, low latency и так далее. Провайдер EF Core должен предоставить большинство имеющихся фичей. Мы начали заниматься этим задолго до EF Core 2.2 и даже выпустили несколько предварительных версий. Мы продолжим разработку провайдера параллельно с EF Core 3.0.
-
Поддержка C# 8.0. В C# 8.0 есть несколько полезных нововведений вроде async streams (включая
await foreach
) и nullable reference types, поддержать которые стоит в EF Core. -
Реверсинжиниринг базы данных в типы-запросы. В EF Core 2.1 добавилась поддержка типов-запросов, представляющих данные, которые можно прочитать из базы, но нельзя обновить. Они отлично подходят для моделирования представлений (view) в SQL базах данных, и поэтому в EF Core 3.0 хочется заняться автоматизацией их создания.
-
Property Bag Entities. Эта добавляет сущности, которые хранят данные не в обычных свойствах, а в индексированных, и могут использовать экземпляры одного и того же класса в .NET (например, что-то вроде
Dictionary<string, object>
) для отображения множества разных типов сущностей в одной и той же модели EF Core. Эта фича — очередная ступенька на пути к полноценным отношениям «многие ко многим» без использования объединяющих сущностей — то есть одной из самых ожидаемых фичей EF Core. -
EF 6.3 on .NET Core. Понятно, что сейчас существует множество приложений, использующих EF, и их портирование на EF Core только для того, чтобы получить какие-то преимущества от использования .NET Core, иногда требует больших усилий. Поэтому мы будем адаптировать следующую версию EF 6 для того, чтобы она тоже начала работать на .NET Core 3.0. Это делается для того, чтобы сподвигнуть разработчиков на портирование своих приложений так, чтобы при этом пришлось изменять как можно меньше кода. Конечно, при этом возникнет ряд ограничений (например, потребуются новые провайдеры и поддержка пространственных данных не включится для SQL Server). Кроме того, мы не планируем добавлять в EF 6 никаких дополнительных фичей.
Заключение
Команда EF благодарит сообщество за качественную обратную связь и содействие в разработке, которые в конце концов привели к появлению EF Core 2.2. Как всегда, напоминаем, что новые ишшуи можно добавлять прямо в наш трекер. Спасибо!
Не забывайте, что билеты на DotNext с первого января подорожают. Personal — на тысячу, а Standard — на две тысячи. Подробности про Early Bird — на сайте.
Автор: olegchir