Критические изменения в EF Core 9 (EF9)
На этой странице описаны изменения API и поведения, которые могут нарушить обновление существующих приложений с EF Core 8 до EF Core 9. Проверьте предыдущие критические изменения при обновлении из более ранней версии EF Core:
- Критические изменения в EF Core 8
- Критические изменения в EF Core 7
- Критические изменения в EF Core 6
Целевая платформа
EF Core 9 предназначен для .NET 8. Это означает, что существующие приложения, предназначенные для .NET 8, могут продолжать делать это. Приложения, предназначенные для более старых версий .NET, .NET Core и платформа .NET Framework, должны быть предназначены для .NET 8 или .NET 9 для использования EF Core 9.
Итоги
Примечание.
Если вы используете Azure Cosmos DB, ознакомьтесь с отдельным разделом ниже в Azure Cosmos DB с критическими изменениями.
Критические изменения | Воздействие |
---|---|
EF.Functions.Unhex() Теперь возвращается byte[]? |
Низкая |
Проверено arity аргументов null в SqlFunctionExpression | Низкая |
ToString() Метод теперь возвращает пустую строку для null экземпляров |
Низкая |
Зависимости общей платформы были обновлены до версии 9.0.x | Низкая |
Изменения низкой степени влияния
EF.Functions.Unhex()
Теперь возвращается byte[]?
Старое поведение
Функция EF.Functions.Unhex()
была ранее аннотирована для возврата byte[]
.
Новое поведение
Начиная с EF Core 9.0, Unhex() теперь заметен для возврата byte[]?
.
Почему
Unhex()
преобразуется в функцию SQLite unhex
, которая возвращает значение NULL для недопустимых входных данных. В результате Unhex()
возвращено null
для этих случаев в нарушение заметки.
Устранение проблем
Если вы уверены, что текстовое содержимое, переданное для Unhex()
представления допустимой шестнадцатеричной строки, можно просто добавить оператор null-forgiving в качестве утверждения о том, что вызов никогда не вернет значение NULL:
var binaryData = await context.Blogs.Select(b => EF.Functions.Unhex(b.HexString)!).ToListAsync();
В противном случае добавьте проверку среды выполнения на значение NULL для возвращаемого значения Unhex().
Проверено arity аргументов null в SqlFunctionExpression
Старое поведение
Ранее можно было создать SqlFunctionExpression
с другим числом аргументов и аргументами распространения значений NULL.
Новое поведение
Начиная с EF Core 9.0, EF теперь выдает, если число аргументов и аргументов распространения null не совпадает.
Почему
Не совпадающее число аргументов и аргументов распространения null может привести к непредвиденному поведению.
Устранение проблем
Убедитесь, что число argumentsPropagateNullability
элементов совпадает с числом arguments
элементов. Если сомнение используется false
для аргумента NULL.
ToString()
Метод теперь возвращает пустую строку для null
экземпляров
Старое поведение
Ранее EF вернул несогласованные результаты для ToString()
метода при значении null
аргумента. Например, ToString()
для свойства с null
возвращаемым null
значением, но для выражений, не являющихся свойствамиbool?
, значение null
которого было возвращеноTrue
bool?
. Поведение также было несогласовано для других типов данных, например ToString()
для null
перечисления значений, возвращаемых пустой строкой.
Новое поведение
Начиная с EF Core 9.0 ToString()
метод теперь последовательно возвращает пустую строку во всех случаях, когда значение аргумента равно null
.
Почему
Старое поведение было несогласованным в разных типах данных и ситуациях, а также не совпадало с поведением C#.
Устранение проблем
Чтобы вернуться к старому поведению, переопределите запрос соответствующим образом:
var newBehavior = context.Entity.Select(x => x.NullableBool.ToString());
var oldBehavior = context.Entity.Select(x => x.NullableBool == null ? null : x.NullableBool.ToString());
Зависимости общей платформы были обновлены до версии 9.0.x
Старое поведение
Приложения, использующие Microsoft.NET.Sdk.Web
пакет SDK и targetting net8.0, разрешают такие пакеты, как System.Text.Json
, Microsoft.Extensions.Logging
Microsoft.Extensions.Caching.Memory
Microsoft.Extensions.Configuration.Abstractions
и Microsoft.Extensions.DependencyModel
из общей платформы, поэтому эти сборки обычно не будут развертываться с приложением.
Новое поведение
Хотя EF Core 9.0 по-прежнему поддерживает net8.0, он теперь ссылается на версии System.Text.Json
9.0.x , Microsoft.Extensions.Logging
Microsoft.Extensions.Caching.Memory
Microsoft.Extensions.Configuration.Abstractions
и .Microsoft.Extensions.DependencyModel
Приложения, предназначенные для net8.0, не смогут использовать общую платформу, чтобы избежать развертывания этих сборок.
Почему
Соответствующие версии зависимостей содержат последние исправления безопасности и их использование упрощает модель обслуживания для EF Core.
Устранение проблем
Измените приложение на целевой net9.0, чтобы получить предыдущее поведение.
Критические изменения в Azure Cosmos DB
Обширная работа прошла в том, чтобы сделать поставщик Azure Cosmos DB лучше в 9.0. Изменения включают ряд критически важных изменений; Если вы обновляете существующее приложение, внимательно ознакомьтесь со следующими сведениями.
Изменения высокой степени влияния
Дискриминатор теперь именуется $type
вместо Discriminator
Старое поведение
EF автоматически добавляет дискриминационные свойства в документы JSON, чтобы определить тип сущности, который представляет документ. В предыдущих версиях EF это свойство JSON используется Discriminator
по умолчанию.
Новое поведение
Начиная с EF Core 9.0, дискриминатор теперь называется $type
по умолчанию. Если у вас есть документы в Azure Cosmos DB из предыдущих версий EF, они используют старое Discriminator
именование, а после обновления до EF 9.0 запросы к этим документам завершаются ошибкой.
Почему
Новая практика JSON использует $type
свойство в сценариях, в которых необходимо определить тип документа. Например. System.Text.Json в NET также поддерживает полиморфизм, используя $type
в качестве имени свойства по умолчанию (docs). Чтобы выровнять остальную часть экосистемы и упростить взаимодействие с внешними инструментами, было изменено значение по умолчанию.
Устранение проблем
Самый простой способ устранения рисков заключается в том, чтобы просто настроить имя дискриминационных свойств Discriminator
так же, как и раньше:
modelBuilder.Entity<Session>().HasDiscriminator<string>("Discriminator");
Это делается для всех типов сущностей верхнего уровня, что делает EF так же, как и раньше.
На этом этапе вы также можете обновить все документы, чтобы использовать новое $type
именование.
Теперь id
свойство содержит только свойство ключа EF по умолчанию
Старое поведение
Ранее EF вставляет дискриминационные значения типа сущности в id
свойство документа. Например, если вы сохранили тип сущности со свойством Blog
Id
, содержащим 8, свойство JSON id
будет содержать Blog|8
.
Новое поведение
Начиная с EF Core 9.0 свойство JSON id
больше не содержит дискриминационных значений и содержит только значение свойства ключа. В приведенном выше примере свойство JSON id
будет просто 8
. Если у вас есть документы в Azure Cosmos DB из предыдущих версий EF, они имеют дискриминационное значение в свойстве JSON id
, а после обновления до EF 9.0 запросы к этим документам завершаются ошибкой.
Почему
Поскольку свойство JSON id
должно быть уникальным, дискриминатор ранее был добавлен в него, чтобы разрешить различным сущностям с одинаковым значением ключа существовать. Например, это позволило иметь как a, Blog
так и Post
свойство со Id
значением 8 в одном контейнере и секции. Это лучше соответствует шаблонам моделирования данных реляционной базы данных, где каждый тип сущности сопоставляется с собственной таблицей и поэтому имеет собственное пространство ключей.
EF 9.0 обычно изменил сопоставление, чтобы быть более согласованным с общими методиками и ожиданиями NoSQL Azure Cosmos DB, а не соответствовать ожиданиям пользователей, поступающих от реляционных баз данных. Кроме того, наличие дискриминационных значений в id
свойстве затрудняет взаимодействие внешних средств и систем с документами JSON, созданными EF; такие внешние системы обычно не знают о дискриминационных значениях EF, которые по умолчанию являются производными от типов .NET.
Устранение проблем
Проще всего настроить EF для включения дискриминационных в свойство JSON id
, как и раньше. Для этой цели был введен новый параметр конфигурации:
modelBuilder.Entity<Session>().HasDiscriminatorInJsonId();
Это делается для всех типов сущностей верхнего уровня, что делает EF так же, как и раньше.
На этом этапе вы также можете обновить все документы, чтобы переписать их свойство JSON id
. Обратите внимание, что это возможно только в том случае, если сущности разных типов не используют одно и то же значение идентификатора в одном контейнере.
Изменения средней степени влияния
Синхронизация операций ввода-вывода с помощью поставщика Azure Cosmos DB больше не поддерживается
Старое поведение
Ранее вызов синхронных методов, таких ToList
как или SaveChanges
вызов EF Core, блокируют синхронно использование .GetAwaiter().GetResult()
при выполнении асинхронных вызовов в пакете SDK Azure Cosmos DB. Это может привести к взаимоблокировке.
Новое поведение
Начиная с EF Core 9.0 EF теперь вызывается по умолчанию при попытке использовать синхронный ввод-вывод. Сообщение об исключении — "Azure Cosmos DB не поддерживает синхронный ввод-вывод. Не забудьте использовать и правильно ожидать только асинхронные методы при использовании Entity Framework Core для доступа к Azure Cosmos DB. Дополнительные сведения см. в статье https://aka.ms/ef-cosmos-nosync ".
Почему
Синхронная блокировка асинхронных методов может привести к взаимоблокировке, а пакет SDK Azure Cosmos DB поддерживает только асинхронные методы.
Устранение проблем
В EF Core 9.0 ошибка может быть отключена с помощью следующих способов:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.ConfigureWarnings(w => w.Ignore(CosmosEventId.SyncNotSupported));
}
Это говорится, что приложения должны перестать использовать API синхронизации с Azure Cosmos DB, так как это не поддерживается пакетом SDK Azure Cosmos DB. Возможность подавления исключения будет удалена в будущем выпуске EF Core, после чего единственным вариантом будет использование асинхронных API.
Теперь запросы SQL должны проектируемые значения JSON напрямую
Старое поведение
Ранее EF создал запросы, такие как следующие:
SELECT c["City"] FROM root c
Такие запросы приводят к тому, что Azure Cosmos DB упаковывает каждый результат в объект JSON следующим образом:
[
{
"City": "Berlin"
},
{
"City": "México D.F."
}
]
Новое поведение
Начиная с EF Core 9.0, EF теперь добавляет VALUE
модификатор в запросы следующим образом:
SELECT VALUE c["City"] FROM root c
Такие запросы приводят к тому, что Azure Cosmos DB возвращает значения напрямую без упаковки:
[
"Berlin",
"México D.F."
]
Если приложение использует запросы SQL, такие запросы, скорее всего, будут нарушены после обновления до EF 9.0, так как они не включают VALUE
модификатор.
Почему
Упаковка каждого результата в дополнительный объект JSON может привести к снижению производительности в некоторых сценариях, раздувает полезные данные результата JSON и не является естественным способом работы с Azure Cosmos DB.
Устранение проблем
Чтобы устранить эту проблему, просто добавьте VALUE
модификатор в проекции запросов SQL, как показано выше.
Неопределенные результаты теперь автоматически фильтруются из результатов запроса
Старое поведение
Ранее EF создал запросы, такие как следующие:
SELECT c["City"] FROM root c
Такие запросы приводят к тому, что Azure Cosmos DB упаковывает каждый результат в объект JSON следующим образом:
[
{
"City": "Berlin"
},
{
"City": "México D.F."
}
]
Если какой-либо из результатов не определен (например City
, свойство отсутствует в документе), возвращается пустой документ, и EF возвращается null
для этого результата.
Новое поведение
Начиная с EF Core 9.0, EF теперь добавляет VALUE
модификатор в запросы следующим образом:
SELECT VALUE c["City"] FROM root c
Такие запросы приводят к тому, что Azure Cosmos DB возвращает значения напрямую без упаковки:
[
"Berlin",
"México D.F."
]
Поведение Azure Cosmos DB заключается в автоматическом фильтрации undefined
значений из результатов. Это означает, что если один из City
свойств отсутствует в документе, запрос вернет только один результат, а не два результата, с одним из null
них.
Почему
Упаковка каждого результата в дополнительный объект JSON может привести к снижению производительности в некоторых сценариях, раздувает полезные данные результата JSON и не является естественным способом работы с Azure Cosmos DB.
Устранение проблем
Если получение null
значений для неопределенных результатов важно для приложения, выполните undefined
объединение значений с null
использованием нового EF.Functions.Coalesce
оператора:
var users = await context.Customer
.Select(c => EF.Functions.CoalesceUndefined(c.City, null))
.ToListAsync();
Неправильно переведенные запросы больше не переводятся
Старое поведение
Ранее ef переведенные запросы, такие как следующие:
var sessions = await context.Sessions
.Take(5)
.Where(s => s.Name.StartsWith("f"))
.ToListAsync();
Однако преобразование SQL для этого запроса было неверным:
SELECT c
FROM root c
WHERE ((c["Discriminator"] = "Session") AND STARTSWITH(c["Name"], "f"))
OFFSET 0 LIMIT @__p_0
В SQL WHERE
предложение вычисляется перед OFFSET
предложением и LIMIT
предложениями, Take
но в приведенном выше запросе LINQ оператор отображается перед операторомWhere
. В результате такие запросы могут возвращать неверные результаты.
Новое поведение
Начиная с EF Core 9.0 такие запросы больше не переводятся, и создается исключение.
Почему
Неправильные переводы могут привести к повреждению автоматических данных, что может привести к ошибкам в приложении. EF всегда предпочитает быстро завершаться сбоем, вызывая передний план, а не причинять повреждение данных.
Устранение проблем
Если вы были довольны предыдущим поведением и хотели бы выполнить тот же SQL, просто переключите порядок операторов LINQ:
var sessions = await context.Sessions
.Where(s => s.Name.StartsWith("f"))
.Take(5)
.ToListAsync();
К сожалению, Azure Cosmos DB в настоящее время не поддерживает OFFSET
предложения в LIMIT
вложенных запросах SQL, что является правильным переводом исходного запроса LINQ.
Изменения низкой степени влияния
HasIndex
теперь бросает вместо того, чтобы игнорировать
Старое поведение
Ранее вызовы HasIndex были проигнорированы поставщиком EF Cosmos DB.
Новое поведение
Теперь поставщик создает исключение, если HasIndex задано.
Почему
В Azure Cosmos DB все свойства индексируются по умолчанию, и индексирование не требуется указывать. Хотя можно определить настраиваемую политику индексирования, она в настоящее время не поддерживается EF и может выполняться через портал Azure без поддержки EF. Так как HasIndex звонки ничего не делают, они больше не допускаются.
Устранение проблем
Удалите все вызовы HasIndex.
IncludeRootDiscriminatorInJsonId
был HasRootDiscriminatorInJsonId
переименован в после версии 9.0.0-rc.2
Старое поведение
API IncludeRootDiscriminatorInJsonId
появился в версии 9.0.0 rc.1.
Новое поведение
Для окончательного выпуска EF Core 9.0 API был переименован в HasRootDiscriminatorInJsonId
Почему
Другой связанный API был переименован, чтобы начать Has
с, а не Include
, поэтому он был переименован для согласованности.
Устранение проблем
Если код использует IncludeRootDiscriminatorInJsonId
API, просто измените его на ссылку HasRootDiscriminatorInJsonId
.