Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En esta página se documentan los cambios de comportamiento de la API y que pueden interrumpir la actualización de aplicaciones existentes de EF Core 8 a EF Core 9. Asegúrese de revisar los cambios importantes anteriores si va a actualizar desde una versión anterior de EF Core:
Entorno de destino
EF Core 9 tiene como destino .NET 8. Esto significa que las aplicaciones existentes que tienen como destino .NET 8 pueden seguir haciéndolo. Las aplicaciones destinadas a versiones anteriores de .NET, .NET Core y .NET Framework tendrán que tener como destino .NET 8 o .NET 9 para usar EF Core 9.
Resumen
Nota:
Si usa Azure Cosmos DB, consulte la sección separada abajo sobre los cambios importantes de Azure Cosmos DB.
Cambios de impacto alto
Se produce una excepción al aplicar migraciones si hay cambios pendientes en el modelo.
Incidencia de seguimiento n.º 33732
Comportamiento anterior
Si el modelo tiene cambios pendientes en comparación con la última migración, no se aplican con el resto de las migraciones cuando se llama a Migrate.
Comportamiento nuevo
A partir de EF Core 9.0, si el modelo tiene cambios pendientes en comparación con la última migración, se produce una excepción cuando se llama a dotnet ef database update, Migrate o MigrateAsync:
El modelo del contexto "DbContext" tiene cambios pendientes. Agregue una nueva migración antes de actualizar la base de datos. Esta excepción se puede suprimir o registrar pasando el identificador de evento "RelationalEventId.PendingModelChangesWarning" al método "ConfigureWarnings" en "DbContext.OnConfiguring" o "AddDbContext".
Por qué
Olvidar agregar una nueva migración después de realizar cambios en el modelo es un error común que puede ser difícil de diagnosticar en algunos casos. La nueva excepción garantiza que el modelo de la aplicación coincida con la base de datos después de aplicar las migraciones.
Mitigaciones
Hay varias situaciones comunes en las que se puede producir esta excepción:
No hay migraciones en absoluto. Esto es común cuando la base de datos se actualiza a través de otros medios.
- Solución: Si no tiene previsto utilizar migraciones para administrar el esquema de la base de datos, elimine la llamada Migrate o MigrateAsync; de lo contrario, añada una migración.
Hay al menos una migración, pero falta la instantánea del modelo. Esto es habitual para las migraciones creadas manualmente.
- Solución: Añada una nueva migración utilizando las herramientas de EF; esto actualizará la instantánea del modelo.
El desarrollador no modificó el modelo, pero está integrado de forma no determinista, lo que hace que EF lo detecte como modificado. Esto es habitual cuando
new DateTime(),DateTime.Now,DateTime.UtcNowoGuid.NewGuid()se usan en objetos proporcionados para HasData.- Mitigación: agregue una nueva migración, examine su contenido para localizar la causa y reemplace los datos dinámicos por un valor estático codificado de forma estática en el modelo. La migración deberá recrearse después de que se corrija el modelo. Si se deben usar datos dinámicos para la propagación, considere la posibilidad de usar el nuevo patrón de propagación en lugar de HasData.
La última migración se creó para un proveedor diferente al usado para aplicar las migraciones.
- Solución: Este es un caso no compatible. La advertencia se puede suprimir mediante el fragmento de código siguiente, pero es probable que este escenario deje de funcionar en una versión futura de EF Core. La solución recomendada es para generar un conjunto independiente de migraciones para cada proveedor.
Las migraciones se generan, modifican o eligen dinámicamente reemplazando algunos de los servicios de EF.
-
Solución: En este caso, la advertencia es un falso positivo y debe ignorarse:
options.ConfigureWarnings(w => w.Ignore(Microsoft.EntityFrameworkCore.Diagnostics.RelationalEventId.PendingModelChangesWarning))
-
Solución: En este caso, la advertencia es un falso positivo y debe ignorarse:
Está utilizando ASP.NET Core Identity y modificas opciones que afectan al modelo, tales como:
.AddDefaultIdentity<ApplicationUser>(options => { options.Stores.SchemaVersion = IdentitySchemaVersions.Version2; options.Stores.MaxLengthForKeys = 256; options.SignIn.RequireConfirmedAccount = false; })Mitigación: para asegurarse de que las opciones se aplican de forma coherente, la aplicación debe especificarse como proyecto de inicio al ejecutar las herramientas de EF o, como alternativa,
IDesignTimeDbContextFactorydebe implementarse en el proyecto que contieneDbContext:public class DatabaseContextDesignTimeFactory : IDesignTimeDbContextFactory<DatabaseContext> { public DatabaseContext CreateDbContext(string[] args) { var services = new ServiceCollection(); AddIdentity(services); var serviceProvider = services.BuildServiceProvider(); var optionsBuilder = new DbContextOptionsBuilder<DatabaseContext>(); optionsBuilder.UseApplicationServiceProvider(serviceProvider); optionsBuilder.UseSqlServer(); return new DatabaseContext(optionsBuilder.Options); } public static IServiceCollection AddIdentity(IServiceCollection services) { services.AddDefaultIdentity<ApplicationUser>(options => { options.Stores.SchemaVersion = IdentitySchemaVersions.Version2; options.Stores.MaxLengthForKeys = 256; options.SignIn.RequireConfirmedAccount = false; }) .AddRoles<IdentityRole>() .AddEntityFrameworkStores<DatabaseContext>(); return services; } }
Si su caso no se ajusta a ninguno de los anteriores y al añadir una nueva migración se crea la misma migración cada vez o una migración vacía y sigue apareciendo la excepción, cree un pequeño proyecto de reproducción y compártalo con el equipo de EF en una nueva incidencia.
Se produce una excepción al aplicar migraciones en una transacción explícita
Problema de Seguimiento #17578
Comportamiento anterior
Para aplicar migraciones de forma resiliente, se usó el siguiente patrón:
await dbContext.Database.CreateExecutionStrategy().ExecuteAsync(async () =>
{
await using var transaction = await dbContext.Database.BeginTransactionAsync(cancellationToken);
await dbContext.Database.MigrateAsync(cancellationToken);
await transaction.CommitAsync(cancellationToken);
});
Comportamiento nuevo
A partir de EF Core 9.0, las llamadas Migrate y MigrateAsync iniciarán una transacción y ejecutarán los comandos mediante un ExecutionStrategy y, si la aplicación usa el patrón anterior, se produce una excepción:
Se generó un error para la advertencia "Microsoft.EntityFrameworkCore.Migrations.MigrationsUserTransactionWarning": Se inició una transacción antes de aplicar migraciones. Esto evita que se adquiera un bloqueo de base de datos y, por tanto, la base de datos no se protegerá de aplicaciones de migración simultáneas. EF ya administra las transacciones y la estrategia de ejecución según sea necesario. Elimine la transacción externa. Esta excepción se puede suprimir o registrar pasando el identificador de evento "RelationalEventId.MigrationsUserTransactionWarning" al método "ConfigureWarnings" en "DbContext.OnConfiguring" o "AddDbContext".
Por qué
El uso de una transacción explícita impide que se adquiera un bloqueo de base de datos y, por tanto, la base de datos no se protegerá de aplicaciones de migración simultáneas, también limita EF sobre cómo puede administrar las transacciones internamente.
Mitigaciones
Si hay solo una llamada a la base de datos dentro de la transacción, elimine la transacción externa y ExecutionStrategy:
await dbContext.Database.MigrateAsync(cancellationToken);
De lo contrario, si el escenario requiere una transacción explícita y tiene otro mecanismo implementado para evitar la aplicación de migración simultánea, omita la advertencia:
options.ConfigureWarnings(w => w.Ignore(RelationalEventId.MigrationsUserTransactionWarning))
Cambios de impacto medio
Microsoft.EntityFrameworkCore.Design no encontrado al usar herramientas EF
Seguimiento de problema n.º 35265
Comportamiento anterior
Anteriormente, las herramientas de EF requerían que se las hiciera referencia de la siguiente manera: Microsoft.EntityFrameworkCore.Design.
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="*.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Comportamiento nuevo
A partir de .NET SDK 9.0.200, se produce una excepción cuando se invoca una herramienta ef:
No se pudo cargar el archivo ni el ensamblado "Microsoft.EntityFrameworkCore.Design, Culture=neutral, PublicKeyToken=null". El sistema no puede encontrar el archivo especificado.
Por qué
Las herramientas de EF se basaban en un comportamiento no documentado del SDK de .NET que provocaba que los recursos privados se incluyeran en el archivo .deps.json generado. Esto se corrigió en sdk#45259. Desafortunadamente, el cambio de EF para solucionar este problema no cumple con el estándar de servicio en EF 9.0.x, por lo que se corregirá en EF 10.
Mitigaciones
Como solución provisional antes del lanzamiento de EF 10, puedes marcar la referencia Design de ensamblado como publicable:
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<Publish>true</Publish>
</PackageReference>
Esto la incluirá en el archivo .deps.json generado, pero tiene el efecto secundario de copiar Microsoft.EntityFrameworkCore.Design.dll a las carpetas de salida y de publicación.
Cambios de impacto bajo
EF.Functions.Unhex() ahora devuelve byte[]?
Problema de seguimiento n.º 33864
Comportamiento anterior
La función EF.Functions.Unhex() fue anteriormente anotada para que devolviera byte[].
Comportamiento nuevo
A partir de EF Core 9.0, Unhex() ahora se anota para devolver byte[]?.
Por qué
Unhex() se traduce a la función SQLite unhex, que devuelve NULL para entradas no válidas. Como resultado, Unhex() devuelve null para esos casos, en violación de la anotación.
Mitigaciones
Si está seguro de que el contenido de texto pasado a Unhex() representa una cadena hexadecimal válida, puede simplemente añadir el operador null-forgiving como afirmación de que la invocación nunca devolverá un valor null:
var binaryData = await context.Blogs.Select(b => EF.Functions.Unhex(b.HexString)!).ToListAsync();
De lo contrario, compruebe en tiempo de ejecución si el valor devuelto por Unhex() es null.
Los modelos compilados ahora hacen referencia a métodos de convertidor de valores directamente
Problema de seguimiento n.º 35033
Comportamiento anterior
Anteriormente, al usar convertidores de valores con modelos compilados (mediante dotnet ef dbcontext optimize), EF haría referencia al tipo de convertidor y todo funcionaba correctamente.
public sealed class BooleanToCharConverter() : ValueConverter<bool, char>(v => ConvertToChar(v), v => ConvertToBoolean(v))
{
public static readonly BooleanToCharConverter Default = new();
private static char ConvertToChar(bool value) // Private method
=> value ? 'Y' : 'N';
private static bool ConvertToBoolean(char value) // Private method
=> value == 'Y';
}
Comportamiento nuevo
A partir de EF Core 9.0, EF genera código que hace referencia directamente a los métodos de conversión. Si estos métodos son privados, se producirá un error en la compilación.
Por qué
Este cambio era necesario para admitir NativeAOT.
Mitigaciones
Haga que los métodos a los que hacen referencia los convertidores de valores sean públicos o internos en lugar de privados.
La aridad de los argumentos de nulabilidad de SqlFunctionExpression validada
Problema de seguimiento n.º 33852
Comportamiento anterior
Anteriormente era posible crear un SqlFunctionExpression con un número diferente de argumentos y argumentos de propagación de nulabilidad.
Comportamiento nuevo
A partir de EF Core 9.0, EF ahora inicia si el número de argumentos y argumentos de propagación de nulabilidad no coinciden.
Por qué
No tener un número coincidente de argumentos y argumentos de propagación de nulabilidad puede provocar un comportamiento inesperado.
Mitigaciones
Asegúrese de que tiene el argumentsPropagateNullability mismo número de elementos que arguments. Cuando se duda se usa false para el argumento de nulabilidad.
el método ToString() devuelve ahora una cadena vacía para las instancias null
Problema de seguimiento n.º 33941
Comportamiento anterior
Anteriormente EF devolvía resultados inconsistentes para el método ToString() cuando el valor del argumento era null. Por ejemplo, ToString() en la propiedad bool? con null dio como resultado null, pero para expresiones que no son propiedades bool? cuyo valor era null devolvía True. El comportamiento también era inconsistente para otros tipos de datos, por ejemplo, ToString() en el valor enum null devolvía cadena vacía.
Comportamiento nuevo
A partir de EF Core 9.0, el método ToString() devuelve ahora sistemáticamente una cadena vacía en todos los casos en que el valor del argumento es null.
Por qué
El comportamiento anterior era incoherente en diferentes tipos de datos y situaciones, además de no coincidir con el comportamiento de C#.
Mitigaciones
Para volver al comportamiento anterior, reescriba la consulta en consecuencia:
var newBehavior = context.Entity.Select(x => x.NullableBool.ToString());
var oldBehavior = context.Entity.Select(x => x.NullableBool == null ? null : x.NullableBool.ToString());
Las dependencias del marco compartido se actualizaron a 9.0.x
Comportamiento anterior
Las aplicaciones que usan el SDK de Microsoft.NET.Sdk.Web y el destino net8.0 resolverían paquetes como System.Text.Json, Microsoft.Extensions.Caching.Memory, Microsoft.Extensions.Configuration.Abstractions, Microsoft.Extensions.Logging y Microsoft.Extensions.DependencyModel desde el marco compartido, por lo que estos ensamblados normalmente no se implementarían con la aplicación.
Comportamiento nuevo
Aunque EF Core 9.0 todavía admite net8.0, ahora hace referencia a las versiones 9.0.x de System.Text.Json, Microsoft.Extensions.Caching.Memory, Microsoft.Extensions.Configuration.Abstractions, Microsoft.Extensions.Logging y Microsoft.Extensions.DependencyModel. Las aplicaciones orientadas a net8.0 no podrán aprovechar el marco compartido para evitar la implantación de estos ensamblados.
Por qué
Las versiones de dependencia coincidentes contienen las últimas correcciones de seguridad y su uso simplifica el modelo de servicio para EF Core.
Mitigaciones
Cambie su aplicación para que apunte a net9.0 para obtener el comportamiento previo.
Las herramientas de EF ya no admiten proyectos de .NET Framework
Problema de seguimiento n.º 37745
Comportamiento anterior
Anteriormente, las herramientas de EF Core (dotnet-ef CLI y herramientas de consola de Package Manager) funcionaban con proyectos destinados a .NET Framework.
Comportamiento nuevo
A partir de EF Core 9.0, las herramientas de EF Core ya no funcionan con proyectos destinados a .NET Framework. Las herramientas producen un error cuando el proyecto de inicio tiene como destino .NET Framework.
Por qué
La versión actual de las herramientas de EF Core funciona con todas las versiones de EF Core compatibles y ya no hay versiones compatibles de EF Core que funcionen en .NET Framework.
Mitigaciones
Actualice el proyecto a .NET de destino (por ejemplo, .NET 8 o posterior). Si el proyecto está destinado actualmente a .NET Framework, consulte la guía de porting para obtener información sobre cómo migrar a .NET.
EF.Constant() y EF.Parameter() ya no funcionan dentro de consultas compiladas
Problema de seguimiento n.º 33674
Comportamiento anterior
En EF Core 8, Constant y Parameter se podría usar dentro de consultas compiladas (CompileQuery y CompileAsyncQuery):
var lookbackDays = 7;
var compiledQuery = EF.CompileAsyncQuery(
(AppDbContext db) => db.Blogs
.Where(b => b.PublishedOn >= DateTime.Today.AddDays(EF.Constant(-lookbackDays))));
Comportamiento nuevo
A partir de EF Core 9.0, el uso de Constant o Parameter dentro de una consulta compilada produce una excepción InvalidCastException.
Unable to cast object of type 'System.Linq.Expressions.ConstantExpression' to type 'System.Linq.Expressions.ParameterExpression'.
Por qué
Se cambió la implementación interna de Constant para evitar la recompilación completa de consultas diferentes para cada valor constante. La implementación anterior introdujo nodos constantes al principio de la canalización de consulta (antes del almacenamiento en caché de consultas), lo que provoca errores de caché costosos cada vez que se pasó un valor diferente a EF.Constant(). La nueva implementación procesa estos métodos en una fase posterior, que no es compatible con las consultas compiladas.
Mitigaciones
Quite la llamada Constant o Parameter de la consulta compilada, o deje de usar una consulta compilada para esa consulta particular. Tenga en cuenta que quitar EF.Constant() hace que el valor se envíe como un parámetro SQL en lugar de insertarse como una constante, lo que puede afectar al rendimiento del plan de consulta.
Cambios de última hora en Azure Cosmos DB
Se ha hecho un trabajo extenso para mejorar el proveedor de Azure Cosmos DB en la versión 9.0. Los cambios incluyen una serie de cambios importantes de alto impacto. Si está actualizando una aplicación existente, lea atentamente lo siguiente.
Cambios de impacto alto
La propiedad del discriminador ahora se llama $type en lugar de Discriminator
Problema de seguimiento n.º 34269
Comportamiento anterior
EF añade automáticamente una propiedad discriminadora a los documentos JSON para identificar el tipo de entidad que representa el documento. En versiones anteriores de EF, esta propiedad JSON solía llamarse Discriminator por defecto.
Comportamiento nuevo
A partir de EF Core 9.0, la propiedad discriminator se llama ahora $type por defecto. Si tiene documentos existentes en Azure Cosmos DB de versiones anteriores de EF, estos usan la nomenclatura anterior de Discriminator y, después de actualizar a EF 9.0, se producirá un error en las consultas en esos documentos.
Por qué
Una práctica emergente de JSON usa una propiedad $type en situaciones en las que es necesario identificar el tipo de documento. Por ejemplo, system.Text.Json de .NET también admite polimorfismo, usando $type como su nombre de propiedad discriminador predeterminado (docs). Para alinearse con el resto del ecosistema y facilitar la interoperabilidad con herramientas externas, se ha cambiado el valor por defecto.
Mitigaciones
La mitigación más fácil es simplemente configurar el nombre de la propiedad discriminador para que sea Discriminator, igual que antes de usar HasDiscriminator:
modelBuilder.Entity<Session>().HasDiscriminator<string>("Discriminator");
Hacer esto para todos sus tipos de entidad de nivel superior hará que EF se comporte igual que antes.
En este punto, si lo desea, también puede actualizar todos sus documentos para utilizar la nueva nomenclatura $type.
La propiedad id ahora contiene solo la propiedad clave de EF por defecto
Problema de seguimiento n.º 34179
Comportamiento anterior
Anteriormente, EF insertaba el valor discriminante de su tipo de entidad en la propiedad id del documento. Por ejemplo, si guardaba un tipo de entidad Blog con una propiedad Id que contenía 8, la propiedad id JSON contendría Blog|8.
Comportamiento nuevo
A partir de EF Core 9.0, la propiedad JSON id ya no contiene el valor discriminador, y solo contiene el valor de su propiedad clave. En el ejemplo anterior, la propiedad JSON id sería simplemente 8. Si tiene documentos existentes en Azure Cosmos DB de versiones anteriores de EF, estos tienen el valor discriminador en la propiedad JSON id y después de actualizar a EF 9.0, se producirá un error en las consultas en esos documentos.
Por qué
Dado que la propiedad JSON id debe ser única, el discriminador se añadió anteriormente para permitir la existencia de diferentes entidades con el mismo valor clave. Por ejemplo, esto permitía tener tanto a Blog como a Post con una propiedad Id que contuviera el valor 8 dentro del mismo contenedor y partición. Esto se ajustaba mejor a los patrones de modelado de datos de las bases de datos relacionales, donde cada tipo de entidad se asigna a su propia tabla y, por lo tanto, tiene su propio espacio de claves.
En general, EF 9.0 cambió la asignación para que se ajustara más a las prácticas y expectativas habituales de Azure Cosmos DB NoSQL, en lugar de corresponderse con las expectativas de los usuarios procedentes de bases de datos relacionales. Además, tener el valor discriminador en la propiedad id dificultaba la interacción de herramientas y sistemas externos con documentos JSON generados por EF; estos sistemas externos no son generalmente conscientes de los valores discriminadores de EF, que se derivan por defecto de tipos de .NET.
Mitigaciones
La mitigación más fácil es simplemente configurar EF para incluir el discriminador en la propiedad JSON id , como antes de usar HasDiscriminatorInJsonId. Para ello se ha introducido una nueva opción de configuración:
modelBuilder.Entity<Session>().HasDiscriminatorInJsonId();
Hacer esto para todos sus tipos de entidad de nivel superior hará que EF se comporte igual que antes.
En este punto, si lo desea, también puede actualizar todos sus documentos para reescribir su propiedad JSON id. Tenga en cuenta que esto solo es posible si las entidades de diferentes tipos no comparten el mismo valor de identificador dentro del mismo contenedor.
La propiedad JSON id se asigna a la clave.
Problema de seguimiento n.º 34179
Comportamiento anterior
Anteriormente, EF creó una propiedad sombra mapeada a la propiedad JSON id, a menos que una de las propiedades se mapease a id explícitamente.
Comportamiento nuevo
A partir de EF Core 9, la propiedad clave se asignará a la propiedad JSON id por convención, si es posible. Esto significa que la propiedad key ya no se conservará en el documento con un nombre diferente pero con el mismo valor, por lo que el código no EF que utilice los documentos y dependa de la presencia de esta propiedad ya no funcionará correctamente.
Por qué
EF 9.0 ha cambiado en general la asignación para que se ajuste más a las prácticas y expectativas comunes de Azure Cosmos DB NoSQL. Y no es habitual almacenar el valor de clave dos veces en el documento.
Mitigaciones
Si desea conservar el comportamiento de EF Core 8, la mitigación más sencilla es usar HasShadowId, una nueva opción de configuración que se ha introducido para este propósito:
modelBuilder.Entity<Session>().HasShadowId();
Hacer esto para todos sus tipos de entidad de nivel superior hará que EF se comporte igual que antes. O bien, puede aplicarlo a todos los tipos de entidad del modelo con una llamada mediante HasShadowIds:
modelBuilder.HasShadowIds();
Cambios de impacto medio
Ya no se admite la E/S de sincronización mediante el proveedor de Azure Cosmos DB
Problema de seguimiento n° 32563
Comportamiento anterior
Anteriormente, llamar a métodos sincrónicos como ToList o SaveChanges haría que EF Core se bloqueara sincrónicamente mediante .GetAwaiter().GetResult() al ejecutar llamadas asincrónicas en el SDK de Azure Cosmos DB. Esto puede provocar un interbloqueo.
Comportamiento nuevo
A partir de EF Core 9.0, EF ahora lanza una excepción de forma predeterminada al intentar usar la E/S sincrónica. El mensaje de excepción es "Azure Cosmos DB no admite E/S sincrónica. Asegúrese de usar y esperar correctamente solo métodos asincrónicos al usar Entity Framework Core para acceder a Azure Cosmos DB. Para más información, vea https://aka.ms/ef-cosmos-nosync".
Por qué
El bloqueo sincrónico en métodos asincrónicos puede dar lugar a un deadlock, y el SDK de Azure Cosmos DB solo admite métodos asincrónicos.
Mitigaciones
En EF Core 9.0, el error se puede suprimir con:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.ConfigureWarnings(w => w.Ignore(CosmosEventId.SyncNotSupported));
}
Dicho esto, las aplicaciones deben dejar de usar las API de sincronización con Azure Cosmos DB, ya que no es compatible con el SDK de Azure Cosmos DB. La capacidad de suprimir la excepción se quitará en una versión futura de EF Core, después de la cual la única opción será usar API asincrónicas.
Las consultas SQL ahora deben proyectar valores JSON directamente
Problema de seguimiento n.º 25527
Comportamiento anterior
Anteriormente, EF generaba consultas como la siguiente:
SELECT c["City"] FROM root c
Estas consultas hacen que Azure Cosmos DB encapsular cada resultado en un objeto JSON, como se indica a continuación:
[
{
"City": "Berlin"
},
{
"City": "México D.F."
}
]
Comportamiento nuevo
A partir de EF Core 9.0, EF añade ahora el modificador VALUE a las consultas de la siguiente forma:
SELECT VALUE c["City"] FROM root c
Estas consultas hacen que Azure Cosmos DB devuelvan los valores directamente, sin encapsularse:
[
"Berlin",
"México D.F."
]
Si su aplicación hace uso de consultas SQL, es probable que dichas consultas no funcionen tras la actualización a EF 9.0, ya que no incluyen el modificador VALUE.
Por qué
Encapsular cada resultado en un objeto JSON adicional puede provocar una degradación del rendimiento en algunos escenarios, hincha la carga del resultado JSON y no es la manera natural de trabajar con Azure Cosmos DB.
Mitigaciones
Para evitarlo, basta con añadir el modificador VALUE a las proyecciones de las consultas SQL, como se muestra más arriba.
Los resultados no definidos ahora se filtran automáticamente de los resultados de las consultas
Problema de seguimiento n.º 25527
Comportamiento anterior
Anteriormente, EF generaba consultas como la siguiente:
SELECT c["City"] FROM root c
Estas consultas hacen que Azure Cosmos DB encapsular cada resultado en un objeto JSON, como se indica a continuación:
[
{
"City": "Berlin"
},
{
"City": "México D.F."
}
]
Si alguno de los resultados era indefinido (por ejemplo, la propiedad City no estaba presente en el documento), se devolvía un documento vacío y EF regresaba null para ese resultado.
Comportamiento nuevo
A partir de EF Core 9.0, EF añade ahora el modificador VALUE a las consultas de la siguiente forma:
SELECT VALUE c["City"] FROM root c
Estas consultas hacen que Azure Cosmos DB devuelvan los valores directamente, sin encapsularse:
[
"Berlin",
"México D.F."
]
El comportamiento de Azure Cosmos DB consiste en filtrar automáticamente los valores de undefined de los resultados; esto significa que si falta una de las propiedades City en el documento, la consulta devolvería un solo resultado, en lugar de dos resultados, con uno null.
Por qué
Encapsular cada resultado en un objeto JSON adicional puede provocar una degradación del rendimiento en algunos escenarios, hincha la carga del resultado JSON y no es la manera natural de trabajar con Azure Cosmos DB.
Mitigaciones
Si obtener valores null para resultados no definidos es importante para su aplicación, agrupe los valores undefined en null con el nuevo operador EF.Functions.Coalesce:
var users = await context.Customer
.Select(c => EF.Functions.CoalesceUndefined(c.City, null))
.ToListAsync();
Las consultas traducidas incorrectamente ya no se traducen
Problema de seguimiento n.º 34123
Comportamiento anterior
Anteriormente, EF traducía consultas como la siguiente:
var sessions = await context.Sessions
.Take(5)
.Where(s => s.Name.StartsWith("f"))
.ToListAsync();
Sin embargo, la traducción SQL de esta consulta era incorrecta:
SELECT c
FROM root c
WHERE ((c["Discriminator"] = "Session") AND STARTSWITH(c["Name"], "f"))
OFFSET 0 LIMIT @__p_0
En SQL, la cláusula WHERE se evalúa antes que las cláusulas OFFSET y LIMIT, pero en la consulta LINQ anterior, el operador Take aparece antes que el operador Where. Como resultado, estas consultas podrían devolver resultados incorrectos.
Comportamiento nuevo
A partir de EF Core 9.0, estas consultas ya no se traducen y se lanza una excepción.
Por qué
Las traducciones incorrectas pueden causar corrupción silenciosa de datos, lo que puede introducir errores difíciles de detectar en su aplicación. EF siempre prefiere fracasar y responder rápido a los errores lanzándose por adelantado antes que causar posiblemente corrupción de datos.
Mitigaciones
Si estuviera satisfecho con el comportamiento anterior y quiere ejecutar el mismo SQL, simplemente cambie el orden de los operadores LINQ:
var sessions = await context.Sessions
.Where(s => s.Name.StartsWith("f"))
.Take(5)
.ToListAsync();
Desafortunadamente, Azure Cosmos DB no admite actualmente las cláusulas OFFSET y LIMIT en las subconsultas SQL, que es la traducción adecuada de la consulta LINQ original.
Cambios de impacto bajo
HasIndex ahora lanza una excepción en lugar de ser ignorado
Problema de seguimiento n.º 34023
Comportamiento anterior
Anteriormente, las llamadas a HasIndex eran ignoradas por el proveedor de EF Cosmos DB.
Comportamiento nuevo
Ahora el proveedor lanza si HasIndex se especifica.
Por qué
En Azure Cosmos DB, todas las propiedades se indexan de forma predeterminada y no es necesario especificar ninguna indexación. Aunque es posible definir una directiva de indexación personalizada, esto no es compatible actualmente con EF y se puede realizar a través de la Azure Portal sin compatibilidad con EF. Dado que las llamadas HasIndex no eran útiles, ya no están permitidas.
Mitigaciones
Elimine cualquier llamada a HasIndex.
IncludeRootDiscriminatorInJsonId fue renombrado a HasRootDiscriminatorInJsonId después de 9.0.0-rc.2
Problema de seguimiento n.º 34717
Comportamiento anterior
La API IncludeRootDiscriminatorInJsonId se introdujo en 9.0.0 rc.1.
Comportamiento nuevo
Para la versión final de EF Core 9.0, se cambió el nombre de la API a HasRootDiscriminatorInJsonId
Por qué
Se renombró otra API relacionada para que empezara por Has en lugar de Include, por lo que esta también fue renombrada por coherencia.
Mitigaciones
Si su código usa la API IncludeRootDiscriminatorInJsonId, simplemente cámbielo para que referencie a HasRootDiscriminatorInJsonId en su lugar.
La versión de Newtonsoft.Json a la que se hace referencia se actualizó de 10.0.2 a 13.0.1
Comportamiento anterior
El proveedor de Cosmos hace referencia a Newtonsoft.Json versión 10.0.2.
Comportamiento nuevo
A partir de EF Core 9.0, el proveedor de Cosmos hace referencia a Newtonsoft.Json versión 13.0.1.
Por qué
La versión a la que se hace referencia anteriormente de Newtonsoft.Json tiene vulnerabilidades conocidas. La versión se actualizó para evitar depender de una versión del paquete con problemas de seguridad conocidos.
Mitigaciones
La actualización a Newtonsoft.Json 13.0.1 no debe causar problemas en la mayoría de los casos. Si la aplicación usa Newtonsoft.Json directamente y se basa en una versión anterior específica, puede actualizar la aplicación para que sea compatible con Newtonsoft.Json 13.0.1 o posterior. Consulte las notas de lanzamiento de Newtonsoft.Json para obtener más información sobre los cambios entre versiones.