Cambios importantes incluidos en EF Core 3.0Breaking changes included in EF Core 3.0

Es posible que los siguientes cambios de API y comportamiento interrumpan las aplicaciones actuales cuando se actualicen a la versión 3.0.0.The following API and behavior changes have the potential to break existing applications when upgrading them to 3.0.0. Los cambios que esperamos que solo afecten a proveedores de base de datos se documentan en Cambios para proveedores.Changes that we expect to only impact database providers are documented under provider changes.

ResumenSummary

Cambio importanteBreaking change ImpactoImpact
Las consultas LINQ ya no se evalúan en el clienteLINQ queries are no longer evaluated on the client AltoHigh
EF Core 3.0 tiene como destino .NET Standard 2.1, y no .NET Standard 2.0EF Core 3.0 targets .NET Standard 2.1 rather than .NET Standard 2.0 AltoHigh
La herramienta de línea de comandos de EF Core, dotnet ef, ya no forma parte del SDK de .NET CoreThe EF Core command-line tool, dotnet ef, is no longer part of the .NET Core SDK AltoHigh
DetectChanges respeta los valores de clave generados por el almacénDetectChanges honors store-generated key values AltoHigh
FromSql, ExecuteSql y ExecuteSqlAsync han cambiado de nombreFromSql, ExecuteSql, and ExecuteSqlAsync have been renamed AltoHigh
Los tipos de consulta se consolidan con tipos de entidadQuery types are consolidated with entity types AltoHigh
Entity Framework Core ya no forma parte del marco compartido ASP.NET CoreEntity Framework Core is no longer part of the ASP.NET Core shared framework MediumMedium
Las eliminaciones en cascada ahora se realizan inmediatamente de forma predeterminadaCascade deletions now happen immediately by default MediumMedium
La carga diligente de entidades relacionadas ahora se realiza en una sola consultaEager loading of related entities now happens in a single query MediumMedium
DeleteBehavior.Restrict tiene una semántica más limpiaDeleteBehavior.Restrict has cleaner semantics MediumMedium
La API de configuración para las relaciones de tipo de propiedad ha cambiadoConfiguration API for owned type relationships has changed MediumMedium
Cada propiedad usa la generación de claves enteras en memoria independienteEach property uses independent in-memory integer key generation MediumMedium
Las consultas sin seguimiento ya no realizan la resolución de la identidadNo-tracking queries no longer perform identity resolution MediumMedium
Cambios en la API de metadatosMetadata API changes MediumMedium
Cambios en la API de metadatos específicos del proveedorProvider-specific Metadata API changes MediumMedium
Se ha quitado el elemento UseRowNumberForPagingUseRowNumberForPaging has been removed MediumMedium
Cuando el método FromSql se usa con un procedimiento almacenado no se puede redactarFromSql method when used with stored procedure cannot be composed MediumMedium
Solo se pueden especificar métodos de FromSql en raíces de consultaFromSql methods can only be specified on query roots BajoLow
La ejecución de consultas se registra en el nivel de depuración RevertidoQuery execution is logged at Debug level Reverted BajoLow
Los valores de clave temporal ya no se establecen en instancias de entidadTemporary key values are no longer set onto entity instances BajoLow
Las entidades dependientes que comparten la tabla con la entidad de seguridad son ahora opcionalesDependent entities sharing the table with the principal are now optional BajoLow
Todas las entidades que compartan una tabla con una columna de token de simultaneidad tienen que asignarla a una propiedadAll entities sharing a table with a concurrency token column have to map it to a property BajoLow
Las propiedades heredadas de tipos sin asignar se asignan ahora a una única columna para todos los tipos derivadosInherited properties from unmapped types are now mapped to a single column for all derived types BajoLow
La convención de propiedad de clave externa ya no coincide con el mismo nombre que la propiedad de entidad de seguridadThe foreign key property convention no longer matches same name as the principal property BajoLow
La conexión de base de datos ahora se cierra si ya no se usa antes de que se complete TransactionScopeDatabase connection is now closed if not used anymore before the TransactionScope has been completed BajoLow
Los campos de respaldo se usan de forma predeterminadaBacking fields are used by default BajoLow
Inicio de excepciones si se encuentran varios campos de respaldo compatiblesThrow if multiple compatible backing fields are found BajoLow
Los nombres de propiedades de solo campo deben coincidir con el nombre del campoField-only property names should match the field name BajoLow
AddDbContext/AddDbContextPool ya no llaman a AddLogging ni a AddMemoryCacheAddDbContext/AddDbContextPool no longer call AddLogging and AddMemoryCache BajoLow
DbContext.Entry realiza ahora una operación DetectChanges localDbContext.Entry now performs a local DetectChanges BajoLow
El cliente no genera las claves de matriz de cadena y byte de forma predeterminadaString and byte array keys are not client-generated by default BajoLow
ILoggerFactory es ahora un servicio con ámbitoILoggerFactory is now a scoped service BajoLow
En los proxies de carga diferida ya no se supone que las propiedades de navegación están totalmente cargadasLazy-loading proxies no longer assume navigation properties are fully loaded BajoLow
La creación excesiva de proveedores de servicios internos ahora es un error de forma predeterminadaExcessive creation of internal service providers is now an error by default BajoLow
Comportamiento nuevo de HasOne/HasMany llamado con una sola cadenaNew behavior for HasOne/HasMany called with a single string BajoLow
El tipo de valor devuelto para varios métodos asincrónicos se ha cambiado de Task a ValueTaskThe return type for several async methods has been changed from Task to ValueTask BajoLow
La anotación Relational:TypeMapping ahora es simplemente TypeMappingThe Relational:TypeMapping annotation is now just TypeMapping BajoLow
ToTable en un tipo derivado produce una excepciónToTable on a derived type throws an exception BajoLow
EF Core ya no envía pragma para el cumplimiento de SQLite FKEF Core no longer sends pragma for SQLite FK enforcement BajoLow
Microsoft.EntityFrameworkCore.Sqlite ahora depende de SQLitePCLRaw.bundle_e_sqlite3Microsoft.EntityFrameworkCore.Sqlite now depends on SQLitePCLRaw.bundle_e_sqlite3 BajoLow
Los valores GUID se almacenan ahora como TEXT en SQLiteGuid values are now stored as TEXT on SQLite BajoLow
Los valores char se almacenan ahora como TEXT en SQLiteChar values are now stored as TEXT on SQLite BajoLow
Los id. de migración ahora se generan usando el calendario de la referencia cultural invariableMigration IDs are now generated using the invariant culture's calendar BajoLow
La información o los metadatos de la extensión se han quitado de IDbContextOptionsExtensionExtension info/metadata has been removed from IDbContextOptionsExtension BajoLow
LogQueryPossibleExceptionWithAggregateOperator ha cambiado de nombreLogQueryPossibleExceptionWithAggregateOperator has been renamed BajoLow
Clarificación de la API para nombres de restricciones de claves externasClarify API for foreign key constraint names BajoLow
IRelationalDatabaseCreator.HasTables/HasTablesAsync se han hecho públicosIRelationalDatabaseCreator.HasTables/HasTablesAsync have been made public BajoLow
Microsoft.EntityFrameworkCore.Design es ahora un paquete DevelopmentDependencyMicrosoft.EntityFrameworkCore.Design is now a DevelopmentDependency package BajoLow
SQLitePCL.raw se ha actualizado a la versión 2.0.0SQLitePCL.raw updated to version 2.0.0 BajoLow
NetTopologySuite se actualizó a la versión 2.0.0NetTopologySuite updated to version 2.0.0 BajoLow
Se usa Microsoft.Data.SqlClient en lugar de System.Data.SqlClientMicrosoft.Data.SqlClient is used instead of System.Data.SqlClient BajoLow
Se deben configurar varias relaciones de referencia automática ambiguasMultiple ambiguous self-referencing relationships must be configured BajoLow
DbFunction.Schema es NULL o la cadena vacía lo configura para estar en el esquema predeterminado del modeloDbFunction.Schema being null or empty string configures it to be in model's default schema BajoLow

Las consultas LINQ ya no se evalúan en el clienteLINQ queries are no longer evaluated on the client

Problema de seguimiento n.° 14935 Consulte también el problema n.° 12795Tracking Issue #14935 Also see issue #12795

Comportamiento anteriorOld behavior

Antes de 3.0, cuando en EF Core no se podía convertir una expresión que formaba parte de una consulta SQL o un parámetro, la expresión se evaluaba de forma automática en el cliente.Before 3.0, when EF Core couldn't convert an expression that was part of a query to either SQL or a parameter, it automatically evaluated the expression on the client. De forma predeterminada, la evaluación de cliente de expresiones potencialmente costosas solo desencadenaba una advertencia.By default, client evaluation of potentially expensive expressions only triggered a warning.

Comportamiento nuevoNew behavior

A partir de 3.0, en EF Core solo se permite que se evalúen en el cliente las expresiones en la proyección de nivel superior (la última llamada a Select() de la consulta).Starting with 3.0, EF Core only allows expressions in the top-level projection (the last Select() call in the query) to be evaluated on the client. Cuando las expresiones de otra parte de la consulta no se pueden convertir en SQL o un parámetro, se inicia una excepción.When expressions in any other part of the query can't be converted to either SQL or a parameter, an exception is thrown.

Por quéWhy

La evaluación de cliente automática de las consultas permite que se ejecuten muchas consultas incluso si no se pueden convertir elementos importantes de ellas.Automatic client evaluation of queries allows many queries to be executed even if important parts of them can't be translated. Esto puede provocar un comportamiento inesperado y potencialmente dañino que es posible que solo sea evidente en entornos de producción.This behavior can result in unexpected and potentially damaging behavior that may only become evident in production. Por ejemplo, una condición en una llamada a Where() que no se puede convertir puede provocar que todas las filas de la tabla se transfieran desde el servidor de base de datos y que el filtro se aplique en el cliente.For example, a condition in a Where() call which can't be translated can cause all rows from the table to be transferred from the database server, and the filter to be applied on the client. Esta situación puede pasar desapercibida fácilmente si la tabla solo contiene algunas filas en la fase de desarrollo, pero ser más grave cuando la aplicación pase a producción, donde la tabla puede contener millones de filas.This situation can easily go undetected if the table contains only a few rows in development, but hit hard when the application moves to production, where the table may contain millions of rows. Las advertencias de evaluación de cliente también se suelen pasar por alto durante el desarrollo.Client evaluation warnings also proved too easy to ignore during development.

Además de esto, la evaluación de cliente automática puede causar problemas en los que la mejora de la traducción de consultas para expresiones específicas provocaba cambios importantes no deseados entre versiones.Besides this, automatic client evaluation can lead to issues in which improving query translation for specific expressions caused unintended breaking changes between releases.

MitigacionesMitigations

Si una consulta no se puede traducir totalmente, vuelva a escribirla en un formato que se pueda traducir, o bien use AsEnumerable(), ToList() o una función similar para devolver los datos al cliente de forma explícita, donde después se puedan seguir procesando mediante LINQ to Objects.If a query can't be fully translated, then either rewrite the query in a form that can be translated, or use AsEnumerable(), ToList(), or similar to explicitly bring data back to the client where it can then be further processed using LINQ-to-Objects.

EF Core 3.0 tiene como destino .NET Standard 2.1, y no .NET Standard 2.0EF Core 3.0 targets .NET Standard 2.1 rather than .NET Standard 2.0

Problema de seguimiento n.º 15498Tracking Issue #15498

Comportamiento anteriorOld behavior

Antes de la versión 3.0, EF Core tenía como destino .NET Standard 2.0 y se podía ejecutar en todas las plataformas que admitieran dicho estándar, incluido .NET Framework.Before 3.0, EF Core targeted .NET Standard 2.0 and would run on all platforms that support that standard, including .NET Framework.

Comportamiento nuevoNew behavior

A partir de la versión 3.0, EF Core tiene como destino .NET Standard 2.1 y se puede ejecutar en todas las plataformas que admitan dicho estándar.Starting with 3.0, EF Core targets .NET Standard 2.1 and will run on all platforms that support this standard. Esto no incluye .NET Framework.This does not include .NET Framework.

Por quéWhy

Esto forma parte de una decisión estratégica para todas las tecnologías de .NET que tiene como objetivo centrar los esfuerzos en .NET Core y otras plataformas modernas de .NET, como Xamarin.This is part of a strategic decision across .NET technologies to focus energy on .NET Core and other modern .NET platforms, such as Xamarin.

MitigacionesMitigations

Valore la posibilidad de cambiar a una plataforma moderna de .NET.Consider moving to a modern .NET platform. Si esto no es posible, siga usando EF Core 2.1 o EF Core 2.2, puesto que ambas versiones admiten .NET Framework.If this is not possible, then continue to use EF Core 2.1 or EF Core 2.2, both of which support .NET Framework.

Entity Framework Core ya no forma parte del marco compartido ASP.NET CoreEntity Framework Core is no longer part of the ASP.NET Core shared framework

Anuncios del problema de seguimiento n.º 325Tracking Issue Announcements#325

Comportamiento anteriorOld behavior

Antes de ASP.NET Core 3.0, cuando se agregaba una referencia de paquete a Microsoft.AspNetCore.App o Microsoft.AspNetCore.All, se incluía EF Core y algunos de los proveedores de datos de EF Core, como el de SQL Server.Before ASP.NET Core 3.0, when you added a package reference to Microsoft.AspNetCore.App or Microsoft.AspNetCore.All, it would include EF Core and some of the EF Core data providers like the SQL Server provider.

Comportamiento nuevoNew behavior

A partir de la versión 3.0, el marco compartido ASP.NET Core no incluye EF Core ni ningún proveedor de datos de EF Core.Starting in 3.0, the ASP.NET Core shared framework doesn't include EF Core or any EF Core data providers.

Por quéWhy

Antes de este cambio, para obtener EF Core se necesitaban varios pasos en función de si la aplicación se destinaba a ASP.NET Core y SQL Server o no.Before this change, getting EF Core required different steps depending on whether the application targeted ASP.NET Core and SQL Server or not. Además, la actualización de ASP.NET Core forzaba la de EF Core y el proveedor de SQL Server, lo que no siempre es deseable.Also, upgrading ASP.NET Core forced the upgrade of EF Core and the SQL Server provider, which isn't always desirable.

Con este cambio, la experiencia de obtención de EF Core es la misma en todos los proveedores, implementaciones admitidas de .NET y tipos de aplicación.With this change, the experience of getting EF Core is the same across all providers, supported .NET implementations and application types. Ahora los desarrolladores también pueden controlar exactamente cuándo se actualizan EF Core y los proveedores de datos de EF Core.Developers can also now control exactly when EF Core and EF Core data providers are upgraded.

MitigacionesMitigations

Para usar EF Core en una aplicación ASP.NET Core 3.0 o cualquier otra aplicación compatible, debe agregar de forma explícita una referencia de paquete al proveedor de base de datos de EF Core que se va a usar en la aplicación.To use EF Core in an ASP.NET Core 3.0 application or any other supported application, explicitly add a package reference to the EF Core database provider that your application will use.

La herramienta de línea de comandos de EF Core, dotnet ef, ya no forma parte del SDK de .NET CoreThe EF Core command-line tool, dotnet ef, is no longer part of the .NET Core SDK

Problema de seguimiento n.º 14016Tracking Issue #14016

Comportamiento anteriorOld behavior

Antes de 3.0, la herramienta dotnet ef se incluía en el SDK de .NET Core y estaba disponible para usarse desde la línea de comandos de cualquier proyecto sin necesidad de realizar pasos adicionales.Before 3.0, the dotnet ef tool was included in the .NET Core SDK and was readily available to use from the command line from any project without requiring extra steps.

Comportamiento nuevoNew behavior

A partir de la versión 3.0, el SDK de .NET no incluye la herramienta dotnet ef, por lo que antes de poder usarla tendrá que instalarla de forma explícita como una herramienta local o global.Starting in 3.0, the .NET SDK does not include the dotnet ef tool, so before you can use it you have to explicitly install it as a local or global tool.

Por quéWhy

Este cambio nos permite distribuir y actualizar dotnet ef como una herramienta convencional de la CLI de .NET en NuGet, coherente con el hecho de que la versión 3.0 de EF Core también se distribuye siempre como un paquete NuGet.This change allows us to distribute and update dotnet ef as a regular .NET CLI tool on NuGet, consistent with the fact that the EF Core 3.0 is also always distributed as a NuGet package.

MitigacionesMitigations

Para poder administrar las migraciones o aplicar scaffolding a DbContext, instale dotnet-ef como herramienta global:To be able to manage migrations or scaffold a DbContext, install dotnet-ef as a global tool:

  $ dotnet tool install --global dotnet-ef

También se puede obtener una herramienta local cuando se restauran las dependencias de un proyecto que la declara como una dependencia de herramientas mediante un archivo de manifiesto de herramientas.You can also obtain it a local tool when you restore the dependencies of a project that declares it as a tooling dependency using a tool manifest file.

FromSql, ExecuteSql y ExecuteSqlAsync han cambiado de nombreFromSql, ExecuteSql, and ExecuteSqlAsync have been renamed

Problema de seguimiento n.º 10996Tracking Issue #10996

Comportamiento anteriorOld behavior

Antes de EF Core 3.0, estos nombres de métodos se sobrecargaban para funcionar tanto con una cadena normal como con una cadena que se debería interpolar en SQL y parámetros.Before EF Core 3.0, these method names were overloaded to work with either a normal string or a string that should be interpolated into SQL and parameters.

Comportamiento nuevoNew behavior

A partir de la versión EF Core 3.0, use FromSqlRaw, ExecuteSqlRaw y ExecuteSqlRawAsync para crear una consulta con parámetros donde los parámetros se pasan por separado de la cadena de consulta.Starting with EF Core 3.0, use FromSqlRaw, ExecuteSqlRaw, and ExecuteSqlRawAsync to create a parameterized query where the parameters are passed separately from the query string. Por ejemplo:For example:

context.Products.FromSqlRaw(
    "SELECT * FROM Products WHERE Name = {0}",
    product.Name);

Use FromSqlInterpolated, ExecuteSqlInterpolated y ExecuteSqlInterpolatedAsync para crear una consulta con parámetros donde los parámetros se pasan como parte de una cadena de consulta interpolada.Use FromSqlInterpolated, ExecuteSqlInterpolated, and ExecuteSqlInterpolatedAsync to create a parameterized query where the parameters are passed as part of an interpolated query string. Por ejemplo:For example:

context.Products.FromSqlInterpolated(
    $"SELECT * FROM Products WHERE Name = {product.Name}");

Tenga en cuenta que las dos consultas anteriores producirán el mismo código SQL parametrizado con los mismos parámetros SQL.Note that both of the queries above will produce the same parameterized SQL with the same SQL parameters.

Por quéWhy

Las sobrecargas del método como esta facilitan las llamadas accidentales al método de cadena sin procesar cuando la intención era llamar al método de cadena interpolada y viceversa.Method overloads like this make it very easy to accidentally call the raw string method when the intent was to call the interpolated string method, and the other way around. Esto podría resultar en consultas que no se parametrizan cuando deberían.This could result in queries not being parameterized when they should have been.

MitigacionesMitigations

Haga el cambio para usar los nuevos nombres de métodos.Switch to use the new method names.

Cuando el método FromSql se usa con un procedimiento almacenado no se puede redactarFromSql method when used with stored procedure cannot be composed

Problema de seguimiento n.° 15392Tracking Issue #15392

Comportamiento anteriorOld behavior

Antes de EF Core 3.0, el método FromSql intentaba detectar si se podía redactar en el código SQL pasado.Before EF Core 3.0, FromSql method tried to detect if the passed SQL can be composed upon. Cuando el código SQL no se podía redactar, como un procedimiento almacenado, realizaba la evaluación de cliente.It did client evaluation when the SQL was non-composable like a stored procedure. La consulta siguiente funcionaba al ejecutar el procedimiento almacenado en el servidor y aplicar FirstOrDefault en el lado cliente.The following query worked by running the stored procedure on the server and doing FirstOrDefault on the client side.

context.Products.FromSqlRaw("[dbo].[Ten Most Expensive Products]").FirstOrDefault();

Comportamiento nuevoNew behavior

A partir de EF Core 3.0, EF Core no intentará analizar el código SQL.Starting with EF Core 3.0, EF Core will not try to parse the SQL. Por tanto, si va a redactar después de FromSqlRaw/FromSqlInterpolated, EF Core redactará el código SQL generando una subconsulta.So if you are composing after FromSqlRaw/FromSqlInterpolated, then EF Core will compose the SQL by causing sub query. Por tanto, si usa un procedimiento almacenado con la redacción, obtendrá una excepción de sintaxis de SQL no válida.So if you are using a stored procedure with composition then you will get an exception for invalid SQL syntax.

Por quéWhy

EF Core 3.0 no admite la evaluación automática de cliente, ya que era propenso a errores, como se explica aquí.EF Core 3.0 does not support automatic client evaluation, since it was error prone as explained here.

MitigaciónMitigation

Si usa un procedimiento almacenado en FromSqlRaw/FromSqlInterpolated, sabe que no se puede redactar, por lo que puede agregar AsEnumerable/AsAsyncEnumerable justo después de la llamada al método FromSql para evitar cualquier redacción en el lado servidor.If you are using a stored procedure in FromSqlRaw/FromSqlInterpolated, you know that it cannot be composed upon, so you can add AsEnumerable/AsAsyncEnumerable right after the FromSql method call to avoid any composition on server side.

context.Products.FromSqlRaw("[dbo].[Ten Most Expensive Products]").AsEnumerable().FirstOrDefault();

Solo se pueden especificar métodos de FromSql en raíces de consulta.FromSql methods can only be specified on query roots

Problema de seguimiento n.° 15704Tracking Issue #15704

Comportamiento anteriorOld behavior

Antes de EF Core 3.0, el método FromSql podía especificarse en cualquier lugar en la consulta.Before EF Core 3.0, the FromSql method could be specified anywhere in the query.

Comportamiento nuevoNew behavior

A partir de EF Core 3.0, los nuevos métodos FromSqlRaw y FromSqlInterpolated (que reemplazan a FromSql) solo pueden especificarse en las raíces de la consulta, es decir, directamente en DbSet<>.Starting with EF Core 3.0, the new FromSqlRaw and FromSqlInterpolated methods (which replace FromSql) can only be specified on query roots, i.e. directly on the DbSet<>. Si intenta especificarlos en cualquier otro lugar se producirá un error de compilación.Attempting to specify them anywhere else will result in a compilation error.

Por quéWhy

La especificación de FromSql en cualquier otro lugar diferente de DbSet no tenía un significado o valor agregado, y podría causar ambigüedad en ciertos escenarios.Specifying FromSql anywhere other than on a DbSet had no added meaning or added value, and could cause ambiguity in certain scenarios.

MitigacionesMitigations

Las invocaciones de FromSql se deben mover para que estén directamente en el DbSet al que se aplican.FromSql invocations should be moved to be directly on the DbSet to which they apply.

Las consultas sin seguimiento ya no realizan la resolución de la identidadNo-tracking queries no longer perform identity resolution

Problema de seguimiento n.º 13518Tracking Issue #13518

Comportamiento anteriorOld behavior

Antes de EF Core 3.0, se usaba la misma instancia de la entidad para cada aparición de una entidad con un tipo e identificador determinados.Before EF Core 3.0, the same entity instance would be used for every occurrence of an entity with a given type and ID. Este comportamiento coincide con el de las consultas de seguimiento.This matches the behavior of tracking queries. Por ejemplo, esta consulta:For example, this query:

var results = context.Products.Include(e => e.Category).AsNoTracking().ToList();

Esta consulta devolverá la misma instancia de Category para cada elemento Product asociado con la categoría determinada.would return the same Category instance for each Product that is associated with the given category.

Comportamiento nuevoNew behavior

A partir de EF Core 3.0, se crean distintas instancias de la entidad si se encuentra una entidad con un tipo e identificador determinados en varias ubicaciones del gráfico devuelto.Starting with EF Core 3.0, different entity instances will be created when an entity with a given type and ID is encountered at different places in the returned graph. Por ejemplo, la consulta anterior ahora devolverá una nueva instancia de Category para cada elemento Product cuando haya dos productos asociados a la misma categoría.For example, the query above will now return a new Category instance for each Product even when two products are associated with the same category.

Por quéWhy

La resolución de las identidades (es decir, el hecho de determinar que una entidad tiene los mismos tipo e identificador que la entidad encontrada) agrega más rendimiento y sobrecarga de memoria.Identity resolution (that is, determining that an entity has the same type and ID as a previously encountered entity) adds additional performance and memory overhead. Este enfoque suele ser contrario a por qué las consultas sin seguimiento se usan en primer lugar.This usually runs counter to why no-tracking queries are used in the first place. Además, aunque la resolución de las identidades a veces puede resultar útil, no es necesaria si las entidades se van a serializar y enviar a un cliente, algo habitual para las consultas sin seguimiento.Also, while identity resolution can sometimes be useful, it is not needed if the entities are to be serialized and sent to a client, which is common for no-tracking queries.

MitigacionesMitigations

Si se requiere la resolución de identidad, use una consulta de seguimiento.Use a tracking query if identity resolution is required.

La ejecución de consultas se registra en el nivel de depuración RevertidoQuery execution is logged at Debug level Reverted

Problema de seguimiento n.º 14523Tracking Issue #14523

Revertimos este cambio porque la nueva configuración de EF Core 3.0 permite a la aplicación especificar el nivel de registro para cualquier evento.We reverted this change because new configuration in EF Core 3.0 allows the log level for any event to be specified by the application. Por ejemplo, para cambiar el registro de SQL a Debug, configure el nivel de forma explícita en OnConfiguring o AddDbContext:For example, to switch logging of SQL to Debug, explicitly configure the level in OnConfiguring or AddDbContext:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder
        .UseSqlServer(connectionString)
        .ConfigureWarnings(c => c.Log((RelationalEventId.CommandExecuting, LogLevel.Debug)));

Los valores de clave temporal ya no se establecen en instancias de entidadTemporary key values are no longer set onto entity instances

Problema de seguimiento n.º 12378Tracking Issue #12378

Comportamiento anteriorOld behavior

Antes de EF Core 3.0, los valores temporales se asignaban a todas las propiedades de clave para las que posteriormente la base de datos generaba un valor real.Before EF Core 3.0, temporary values were assigned to all key properties that would later have a real value generated by the database. Normalmente, estos valores temporales eran números negativos grandes.Usually these temporary values were large negative numbers.

Comportamiento nuevoNew behavior

A partir de la versión 3.0, en EF Core se almacena el valor de clave temporal como parte de la información de seguimiento de la entidad y la propiedad clave en sí no se modifica.Starting with 3.0, EF Core stores the temporary key value as part of the entity's tracking information, and leaves the key property itself unchanged.

Por quéWhy

Este cambio se ha realizado para evitar que los valores de clave temporales se conviertan erróneamente en permanentes cuando una entidad de la que previamente una instancia de DbContext ha realizado el seguimiento se mueve a otra instancia de DbContext.This change was made to prevent temporary key values from erroneously becoming permanent when an entity that has been previously tracked by some DbContext instance is moved to a different DbContext instance.

MitigacionesMitigations

Las aplicaciones que asignan valores de clave principal a claves externas para crear asociaciones entre entidades pueden depender del comportamiento anterior si las claves principales son generadas por el almacén y pertenecen a entidades en el estado Added.Applications that assign primary key values onto foreign keys to form associations between entities may depend on the old behavior if the primary keys are store-generated and belong to entities in the Added state. Esto se puede evitar con las siguientes situaciones:This can be avoided by:

  • No se usan claves generadas por el almacén.Not using store-generated keys.
  • Se establecen propiedades de navegación para crear relaciones en lugar de establecer valores de clave externa.Setting navigation properties to form relationships instead of setting foreign key values.
  • Se obtienen los valores de clave temporal reales de la información de seguimiento de la entidad.Obtain the actual temporary key values from the entity's tracking information. Por ejemplo, context.Entry(blog).Property(e => e.Id).CurrentValue devolverá el valor temporal aunque no se haya establecido blog.Id.For example, context.Entry(blog).Property(e => e.Id).CurrentValue will return the temporary value even though blog.Id itself hasn't been set.

DetectChanges respeta los valores de clave generados por el almacénDetectChanges honors store-generated key values

Problema de seguimiento n.º 14616Tracking Issue #14616

Comportamiento anteriorOld behavior

Antes de EF Core 3.0, se realizaba el seguimiento en el estado Added de las entidades sin seguimiento detectadas por DetectChanges y se insertaban como una fila nueva cuando se llamaba a SaveChanges.Before EF Core 3.0, an untracked entity found by DetectChanges would be tracked in the Added state and inserted as a new row when SaveChanges is called.

Comportamiento nuevoNew behavior

A partir de EF Core 3.0, si una entidad usa valores de clave generados y se establece un valor de clave, se realizará el seguimiento de la entidad en el estado Modified.Starting with EF Core 3.0, if an entity is using generated key values and some key value is set, then the entity will be tracked in the Modified state. Esto significa que se supone que existe una fila para la entidad y que se actualizará cuando se llame a SaveChanges.This means that a row for the entity is assumed to exist and it will be updated when SaveChanges is called. Si no se establece el valor de clave, o bien si el tipo de entidad no usa claves generadas, se seguirá realizando el seguimiento de la entidad nueva como Added al igual que en las versiones anteriores.If the key value isn't set, or if the entity type isn't using generated keys, then the new entity will still be tracked as Added as in previous versions.

Por quéWhy

Este cambio se ha realizado para que sea más sencillo y coherente trabajar con gráficos de entidades desconectadas mientras se usan claves generadas por el almacén.This change was made to make it easier and more consistent to work with disconnected entity graphs while using store-generated keys.

MitigacionesMitigations

Este cambio puede interrumpir una aplicación si se configura un tipo de entidad para usar claves generadas, pero se establecen de forma explícita valores de clave para las instancias nuevas.This change can break an application if an entity type is configured to use generated keys but key values are explicitly set for new instances. La solución consiste en configurar de forma explícita las propiedades de clave para que no usen valores generados.The fix is to explicitly configure the key properties to not use generated values. Por ejemplo, con la API fluida:For example, with the fluent API:

modelBuilder
    .Entity<Blog>()
    .Property(e => e.Id)
    .ValueGeneratedNever();

O bien con anotaciones de datos:Or with data annotations:

[DatabaseGenerated(DatabaseGeneratedOption.None)]
public string Id { get; set; }

Las eliminaciones en cascada ahora se realizan inmediatamente de forma predeterminadaCascade deletions now happen immediately by default

Problema de seguimiento n.º 10114Tracking Issue #10114

Comportamiento anteriorOld behavior

Antes de la versión 3.0, en EF Core no se aplicaban acciones en cascada (eliminación de entidades dependientes cuando se eliminaba una entidad de seguridad obligatoria o cuando se rompía la relación con una entidad de seguridad obligatoria) hasta que se llamaba a SaveChanges.Before 3.0, EF Core applied cascading actions (deleting dependent entities when a required principal is deleted or when the relationship to a required principal is severed) did not happen until SaveChanges was called.

Comportamiento nuevoNew behavior

A partir de 3.0, en EF Core las acciones en cascada se aplican en cuanto se detecta la condición desencadenadora.Starting with 3.0, EF Core applies cascading actions as soon as the triggering condition is detected. Por ejemplo, como resultado de la llamada a context.Remove() para eliminar una entidad de seguridad, todos los dependientes obligatorios relacionados de los que se realiza el seguimiento también se establecen en Deleted inmediatamente.For example, calling context.Remove() to delete a principal entity will result in all tracked related required dependents also being set to Deleted immediately.

Por quéWhy

Este cambio se ha realizado para mejorar la experiencia en escenarios de auditoría y enlace de datos donde es importante comprender qué entidades se van a eliminar antes de llamar a SaveChanges.This change was made to improve the experience for data binding and auditing scenarios where it is important to understand which entities will be deleted before SaveChanges is called.

MitigacionesMitigations

El comportamiento anterior se puede restaurar mediante opciones de context.ChangedTracker.The previous behavior can be restored through settings on context.ChangedTracker. Por ejemplo:For example:

context.ChangeTracker.CascadeDeleteTiming = CascadeTiming.OnSaveChanges;
context.ChangeTracker.DeleteOrphansTiming = CascadeTiming.OnSaveChanges;

Problema de seguimiento n.º 18022Tracking issue #18022

Comportamiento anteriorOld behavior

Antes de la versión 3.0, la carga diligente de navegaciones de colección a través de operadores Include provocaba la generación de varias consultas en la base de datos relacional, una para cada tipo de entidad relacionada.Before 3.0, eagerly loading collection navigations via Include operators caused multiple queries to be generated on relational database, one for each related entity type.

Comportamiento nuevoNew behavior

A partir de la versión 3.0, EF Core genera una sola consulta con operadores JOIN en las bases de datos relacionales.Starting with 3.0, EF Core generates a single query with JOINs on relational databases.

Por quéWhy

La emisión de varias consultas para implementar una única consulta LINQ provocaba numerosos problemas, incluido el rendimiento negativo, ya que se necesitaban varios recorridos de ida y vuelta a la base de datos, y problemas de coherencia de datos, ya que cada consulta podía observar un estado distinto de la base de datos.Issuing multiple queries to implement a single LINQ query caused numerous issues, including negative performance as multiple database roundtrips were necessary, and data coherency issues as each query could observe a different state of the database.

MitigacionesMitigations

Aunque técnicamente esto no es un cambio importante, podría tener un efecto considerable en el rendimiento de la aplicación cuando una sola consulta contiene un gran número de operadores Include en las navegaciones de la colección.While technically this is not a breaking change, it could have a considerable effect on application performance when a single query contains a large number of Include operator on collection navigations. Vea este comentario para obtener más información y para volver a escribir las consultas de una manera más eficaz.See this comment for more information and for rewriting queries in a more efficient way.

**

DeleteBehavior.Restrict tiene una semántica más limpiaDeleteBehavior.Restrict has cleaner semantics

Problema de seguimiento n.º 12661Tracking Issue #12661

Comportamiento anteriorOld behavior

Antes de la versión 3.0, DeleteBehavior.Restrict creaba claves externas en la base de datos con la semántica Restrict, pero también realizaba una corrección interna de manera no evidente.Before 3.0, DeleteBehavior.Restrict created foreign keys in the database with Restrict semantics, but also changed internal fixup in a non-obvious way.

Comportamiento nuevoNew behavior

A partir de la versión 3.0, DeleteBehavior.Restrict garantiza que las claves externas se crean con la semántica Restrict, es decir, sin cascadas y realizando una infracción de restricción, sin llevar a cabo correcciones internas de EF.Starting with 3.0, DeleteBehavior.Restrict ensures that foreign keys are created with Restrict semantics--that is, no cascades; throw on constraint violation--without also impacting EF internal fixup.

Por quéWhy

Este cambio se realizó para mejorar la experiencia de uso de DeleteBehavior de manera intuitiva sin efectos secundarios inesperados.This change was made to improve the experience for using DeleteBehavior in an intuitive manner, without unexpected side-effects.

MitigacionesMitigations

El comportamiento anterior se puede restaurar con DeleteBehavior.ClientNoAction.The previous behavior can be restored by using DeleteBehavior.ClientNoAction.

Los tipos de consulta se consolidan con tipos de entidadQuery types are consolidated with entity types

Problema de seguimiento n.º 14194Tracking Issue #14194

Comportamiento anteriorOld behavior

Antes de EF Core 3.0, los tipos de consulta eran un medio para consultar los datos que no definen una clave principal de una manera estructurada.Before EF Core 3.0, query types were a means to query data that doesn't define a primary key in a structured way. Es decir, un tipo de consulta se usaba para asignar tipos de entidad sin claves (más probablemente desde una vista, pero posiblemente desde una tabla), mientras que un tipo de entidad estándar se usaba cuando había una clave disponible (más probablemente desde una tabla, pero posiblemente desde una vista).That is, a query type was used for mapping entity types without keys (more likely from a view, but possibly from a table) while a regular entity type was used when a key was available (more likely from a table, but possibly from a view).

Comportamiento nuevoNew behavior

Ahora un tipo de consulta se convierte en un tipo de entidad sin una clave principal.A query type now becomes just an entity type without a primary key. Los tipos de entidad sin clave tienen la misma funcionalidad que los tipos de consulta de las versiones anteriores.Keyless entity types have the same functionality as query types in previous versions.

Por quéWhy

Este cambio se ha realizado para reducir la confusión en torno a la finalidad de los tipos de consulta.This change was made to reduce the confusion around the purpose of query types. En concreto, son tipos de entidad sin clave y, por ello, intrínsecamente son de solo lectura, pero no se deben usar solo porque un tipo de entidad tenga que ser de solo lectura.Specifically, they are keyless entity types and they are inherently read-only because of this, but they should not be used just because an entity type needs to be read-only. Del mismo modo, se suelen asignar a vistas, pero solo porque las vistas no suelen definir claves.Likewise, they are often mapped to views, but this is only because views often don't define keys.

MitigacionesMitigations

Los elementos siguientes de la API ahora están obsoletos:The following parts of the API are now obsolete:

  • ModelBuilder.Query<>() : en su lugar es necesario llamar a ModelBuilder.Entity<>().HasNoKey() para marcar un tipo de entidad como sin claves.ModelBuilder.Query<>() - Instead ModelBuilder.Entity<>().HasNoKey() needs to be called to mark an entity type as having no keys. Esto todavía no se configurará por convención para evitar una configuración incorrecta cuando se espera una clave principal, pero no coincide con la convención.This would still not be configured by convention to avoid misconfiguration when a primary key is expected, but doesn't match the convention.
  • DbQuery<> : en su lugar se debe usar DbSet<>.DbQuery<> - Instead DbSet<> should be used.
  • DbContext.Query<>() : en su lugar se debe usar DbContext.Set<>().DbContext.Query<>() - Instead DbContext.Set<>() should be used.

La API de configuración para las relaciones de tipo de propiedad ha cambiadoConfiguration API for owned type relationships has changed

Problema de seguimiento n.º 12444 Problema de seguimiento n.º 9148 Problema de seguimiento n.º 14153Tracking Issue #12444 Tracking Issue #9148 Tracking Issue #14153

Comportamiento anteriorOld behavior

Antes de EF Core 3.0, la configuración de la relación de propiedad se realizaba directamente después de la llamada a OwnsOne o OwnsMany.Before EF Core 3.0, configuration of the owned relationship was performed directly after the OwnsOne or OwnsMany call.

Comportamiento nuevoNew behavior

A partir de EF Core 3.0, ahora hay una API fluida para configurar una propiedad de navegación para el propietario mediante WithOwner().Starting with EF Core 3.0, there is now fluent API to configure a navigation property to the owner using WithOwner(). Por ejemplo:For example:

modelBuilder.Entity<Order>.OwnsOne(e => e.Details).WithOwner(e => e.Order);

La configuración relacionada con la relación entre el propietario y lo que se posee ahora se debe encadenar después de WithOwner(), de forma similar a cómo se configuran otras relaciones.The configuration related to the relationship between owner and owned should now be chained after WithOwner() similarly to how other relationships are configured. Pero la configuración del propio tipo de propiedad se seguirá encadenando después de OwnsOne()/OwnsMany().While the configuration for the owned type itself would still be chained after OwnsOne()/OwnsMany(). Por ejemplo:For example:

modelBuilder.Entity<Order>.OwnsOne(e => e.Details, eb =>
    {
        eb.WithOwner()
            .HasForeignKey(e => e.AlternateId)
            .HasConstraintName("FK_OrderDetails");
            
        eb.ToTable("OrderDetails");
        eb.HasKey(e => e.AlternateId);
        eb.HasIndex(e => e.Id);

        eb.HasOne(e => e.Customer).WithOne();

        eb.HasData(
            new OrderDetails
            {
                AlternateId = 1,
                Id = -1
            });
    });

Además, la llamada a Entity(), HasOne() o Set() con un tipo de propiedad de destino ahora iniciará una excepción.Additionally calling Entity(), HasOne(), or Set() with an owned type target will now throw an exception.

Por quéWhy

Este cambio se ha realizado para crear una separación más clara entre la configuración del propio tipo de propiedad y la relación con el tipo de propiedad.This change was made to create a cleaner separation between configuring the owned type itself and the relationship to the owned type. A su vez, esto elimina la ambigüedad y la confusión de métodos como HasForeignKey.This in turn removes ambiguity and confusion around methods like HasForeignKey.

MitigacionesMitigations

Cambie la configuración de las relaciones de tipo de propiedad para usar la nueva superficie de API, como se muestra en el ejemplo anterior.Change configuration of owned type relationships to use the new API surface as shown in the example above.

Ahora, las entidades dependientes que comparten la tabla con la entidad de seguridad son opcionalesDependent entities sharing the table with the principal are now optional

Problema de seguimiento n.º 9005Tracking Issue #9005

Comportamiento anteriorOld behavior

Considere el modelo siguiente:Consider the following model:

public class Order
{
    public int Id { get; set; }
    public int CustomerId { get; set; }
    public OrderDetails Details { get; set; }
}

public class OrderDetails
{
    public int Id { get; set; }
    public string ShippingAddress { get; set; }
}

Antes de EF Core 3.0, si OrderDetails era propiedad de Order o estaba asignado explícitamente a la misma tabla, siempre era necesaria una instancia de OrderDetails al agregar un elemento Order nuevo.Before EF Core 3.0, if OrderDetails is owned by Order or explicitly mapped to the same table then an OrderDetails instance was always required when adding a new Order.

Comportamiento nuevoNew behavior

A partir de la versión 3.0, EF Core permite agregar Order sin OrderDetails y asigna todas las propiedades OrderDetails a excepción de la clave principal a columnas que aceptan valores NULL.Starting with 3.0, EF Core allows to add an Order without an OrderDetails and maps all of the OrderDetails properties except the primary key to nullable columns. Al realizar consultas, EF Core establece OrderDetails en null si ninguna de las propiedades necesarias tiene un valor o si no tiene propiedades necesarias más allá de la clave principal y todas las propiedades son null.When querying EF Core sets OrderDetails to null if any of its required properties doesn't have a value or if it has no required properties besides the primary key and all properties are null.

MitigacionesMitigations

Si el modelo tiene una tabla que comparte dependencias con todas las columnas opcionales, pero la navegación que apunta a ella no se espera que sea null, la aplicación debería modificarse para controlar los casos en los que la navegación sea null.If your model has a table sharing dependent with all optional columns, but the navigation pointing to it is not expected to be null then the application should be modified to handle cases when the navigation is null. Si esto no es posible, debería agregarse una propiedad necesaria al tipo de entidad o, al menos, una entidad debería tener un valor distinto a null asignado.If this is not possible a required property should be added to the entity type or at least one property should have a non-null value assigned to it.

Todas las entidades que compartan una tabla con una columna de token de simultaneidad tienen que asignarla a una propiedadAll entities sharing a table with a concurrency token column have to map it to a property

Problema de seguimiento n.º 14154Tracking Issue #14154

Comportamiento anteriorOld behavior

Considere el modelo siguiente:Consider the following model:

public class Order
{
    public int Id { get; set; }
    public int CustomerId { get; set; }
    public byte[] Version { get; set; }
    public OrderDetails Details { get; set; }
}

public class OrderDetails
{
    public int Id { get; set; }
    public string ShippingAddress { get; set; }
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Order>()
        .Property(o => o.Version).IsRowVersion().HasColumnName("Version");
}

Antes de EF Core 3.0, si OrderDetails era propiedad de Order o estaba asignado explícitamente a la misma tabla, si solo se actualizaba OrderDetails, no se actualizaba el valor Version en el cliente y se producía un error en la próxima actualización.Before EF Core 3.0, if OrderDetails is owned by Order or explicitly mapped to the same table then updating just OrderDetails will not update Version value on client and the next update will fail.

Comportamiento nuevoNew behavior

A partir de la versión 3.0, EF Core propaga el nuevo valor Version en Order si posee OrderDetails.Starting with 3.0, EF Core propagates the new Version value to Order if it owns OrderDetails. En caso contrario, se produce una excepción durante la validación del modelo.Otherwise an exception is thrown during model validation.

Por quéWhy

Este cambio se realizó para evitar un valor de token de simultaneidad obsoleto cuando solo se actualiza una de las entidades asignadas a la misma tabla.This change was made to avoid a stale concurrency token value when only one of the entities mapped to the same table is updated.

MitigacionesMitigations

Todas las entidades que comparten la tabla deben incluir una propiedad que se asigna a la columna del token de simultaneidad.All entities sharing the table have to include a property that is mapped to the concurrency token column. Es posible crear una en estado reemplazado:It's possible the create one in shadow-state:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<OrderDetails>()
        .Property<byte[]>("Version").IsRowVersion().HasColumnName("Version");
}

Ahora, las propiedades heredadas de tipos sin asignar se asignan a una única columna para todos los tipos derivadosInherited properties from unmapped types are now mapped to a single column for all derived types

Problema de seguimiento n.º 13998Tracking Issue #13998

Comportamiento anteriorOld behavior

Considere el modelo siguiente:Consider the following model:

public abstract class EntityBase
{
    public int Id { get; set; }
}

public abstract class OrderBase : EntityBase
{
    public int ShippingAddress { get; set; }
}

public class BulkOrder : OrderBase
{
}

public class Order : OrderBase
{
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Ignore<OrderBase>();
    modelBuilder.Entity<EntityBase>();
    modelBuilder.Entity<BulkOrder>();
    modelBuilder.Entity<Order>();
}

Antes de EF Core 3.0, la propiedad ShippingAddress se asignaba a columnas distintas para BulkOrder y Order de forma predeterminada.Before EF Core 3.0, the ShippingAddress property would be mapped to separate columns for BulkOrder and Order by default.

Comportamiento nuevoNew behavior

A partir de la versión3.0, EF Core solo crea una columna para ShippingAddress.Starting with 3.0, EF Core only creates one column for ShippingAddress.

Por quéWhy

El comportamiento anterior no era el esperado.The old behavoir was unexpected.

MitigacionesMitigations

Todavía se puede asignar explícitamente la propiedad a columnas separadas en los tipos derivados:The property can still be explicitly mapped to separate column on the derived types:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Ignore<OrderBase>();
    modelBuilder.Entity<EntityBase>();
    modelBuilder.Entity<BulkOrder>()
        .Property(o => o.ShippingAddress).HasColumnName("BulkShippingAddress");
    modelBuilder.Entity<Order>()
        .Property(o => o.ShippingAddress).HasColumnName("ShippingAddress");
}

La convención de propiedad de clave externa ya no coincide con el mismo nombre que la propiedad de entidad de seguridadThe foreign key property convention no longer matches same name as the principal property

Problema de seguimiento n.º 13274Tracking Issue #13274

Comportamiento anteriorOld behavior

Considere el modelo siguiente:Consider the following model:

public class Customer
{
    public int CustomerId { get; set; }
    public ICollection<Order> Orders { get; set; }
}

public class Order
{
    public int Id { get; set; }
    public int CustomerId { get; set; }
}

Antes de EF Core 3.0, se podía usar la propiedad CustomerId para la clave externa por convención.Before EF Core 3.0, the CustomerId property would be used for the foreign key by convention. Pero si Order es un tipo de propiedad, entonces esto convertiría también a CustomerId en la clave principal, algo que no suele ser lo esperado.However, if Order is an owned type, then this would also make CustomerId the primary key and this isn't usually the expectation.

Comportamiento nuevoNew behavior

A partir de la versión 3.0, EF Core no intenta usar las propiedades de claves externas por convención si tienen el mismo nombre que la propiedad de entidad de seguridad.Starting with 3.0, EF Core doesn't try to use properties for foreign keys by convention if they have the same name as the principal property. Los patrones de nombre de tipo de entidad de seguridad concatenado con el nombre de propiedad de la entidad de seguridad y de nombre de navegación concatenado con el nombre de propiedad de la entidad de seguridad todavía se hacen coincidir.Principal type name concatenated with principal property name, and navigation name concatenated with principal property name patterns are still matched. Por ejemplo:For example:

public class Customer
{
    public int Id { get; set; }
    public ICollection<Order> Orders { get; set; }
}

public class Order
{
    public int Id { get; set; }
    public int CustomerId { get; set; }
}
public class Customer
{
    public int Id { get; set; }
    public ICollection<Order> Orders { get; set; }
}

public class Order
{
    public int Id { get; set; }
    public int BuyerId { get; set; }
    public Customer Buyer { get; set; }
}

Por quéWhy

Este cambio se ha realizado para evitar definir erróneamente una propiedad de clave principal en el tipo de propiedad.This change was made to avoid erroneously defining a primary key property on the owned type.

MitigacionesMitigations

Si la propiedad se ha diseñado para ser la clave externa y, por tanto, parte de la clave principal, se debe configurar explícitamente como tal.If the property was intended to be the foreign key, and hence part of the primary key, then explicitly configure it as such.

Ahora, la conexión de base de datos se cierra si ya no se usa antes de que se complete TransactionScopeDatabase connection is now closed if not used anymore before the TransactionScope has been completed

Problema de seguimiento n.º 14218Tracking Issue #14218

Comportamiento anteriorOld behavior

Antes de EF Core 3.0, si el contexto abría la conexión dentro de TransactionScope, la conexión permanecía abierta mientras el ámbito actual TransactionScope estuviese activo.Before EF Core 3.0, if the context opens the connection inside a TransactionScope, the connection remains open while the current TransactionScope is active.

using (new TransactionScope())
{
    using (AdventureWorks context = new AdventureWorks())
    {
        context.ProductCategories.Add(new ProductCategory());
        context.SaveChanges();

        // Old behavior: Connection is still open at this point
        
        var categories = context.ProductCategories().ToList();
    }
}

Comportamiento nuevoNew behavior

A partir de la versión 3.0, EF Core cierra la conexión en cuanto se deja de usar.Starting with 3.0, EF Core closes the connection as soon as it's done using it.

Por quéWhy

Este cambio permite usar varios contextos en el mismo ámbito TransactionScope.This change allows to use multiple contexts in the same TransactionScope. El comportamiento nuevo también coincide con el de EF6.The new behavior also matches EF6.

MitigacionesMitigations

Si la conexión debe permanecer abierta, una llamada explícita a OpenConnection() asegurará que EF Core no la cierre de forma prematura:If the connection needs to remain open explicit call to OpenConnection() will ensure that EF Core doesn't close it prematurely:

using (new TransactionScope())
{
    using (AdventureWorks context = new AdventureWorks())
    {
        context.Database.OpenConnection();
        context.ProductCategories.Add(new ProductCategory());
        context.SaveChanges();
        
        var categories = context.ProductCategories().ToList();
        context.Database.CloseConnection();
    }
}

Cada propiedad usa la generación de claves enteras en memoria independienteEach property uses independent in-memory integer key generation

Problema de seguimiento n.º 6872Tracking Issue #6872

Comportamiento anteriorOld behavior

Antes de EF Core 3.0, se usaba un generador de valores compartidos para todas las propiedades de clave entera en memoria.Before EF Core 3.0, one shared value generator was used for all in-memory integer key properties.

Comportamiento nuevoNew behavior

A partir de EF Core 3.0, cada propiedad de clave entera obtiene su propio generador de valores cuando se usa la base de datos en memoria.Starting with EF Core 3.0, each integer key property gets its own value generator when using the in-memory database. Además, si se elimina la base de datos, la generación de claves se restablece para todas las tablas.Also, if the database is deleted, then key generation is reset for all tables.

Por quéWhy

Este cambio se ha realizado para alinear la generación de claves en memoria más estrechamente a la generación de claves de base de datos reales y para mejorar la capacidad para aislar las pruebas entre sí cuando se usa la base de datos en memoria.This change was made to align in-memory key generation more closely to real database key generation and to improve the ability to isolate tests from each other when using the in-memory database.

MitigacionesMitigations

Esto puede interrumpir una aplicación que se base en el establecimiento de valores de clave específicos en memoria.This can break an application that is relying on specific in-memory key values to be set. En su lugar, considere la posibilidad de no depender de valores de clave específicos, o bien de actualizar para que coincida con el comportamiento nuevo.Consider instead not relying on specific key values, or updating to match the new behavior.

Los campos de respaldo se usan de forma predeterminadaBacking fields are used by default

Problema de seguimiento n.º 12430Tracking Issue #12430

Comportamiento anteriorOld behavior

Antes de la versión 3.0, incluso si se conocía el campo de respaldo de una propiedad, de forma predeterminada en EF Core se leía y escribía el valor de propiedad mediante los métodos captadores y establecedores de propiedades.Before 3.0, even if the backing field for a property was known, EF Core would still by default read and write the property value using the property getter and setter methods. La excepción era la ejecución de consultas, donde el campo de respaldo se establecía directamente si se conocía.The exception to this was query execution, where the backing field would be set directly if known.

Comportamiento nuevoNew behavior

A partir de EF Core 3.0, si se conoce el campo de respaldo para una propiedad, EF Core siempre la leerá y escribirá mediante el campo de respaldo.Starting with EF Core 3.0, if the backing field for a property is known, then EF Core will always read and write that property using the backing field. Esto podría provocar una interrupción de la aplicación si depende de un comportamiento adicional codificado en los métodos captadores o establecedores.This could cause an application break if the application is relying on additional behavior coded into the getter or setter methods.

Por quéWhy

Este cambio se ha realizado para evitar que EF Core desencadene erróneamente lógica de negocios de forma predeterminada al realizar operaciones de base de datos que implican entidades.This change was made to prevent EF Core from erroneously triggering business logic by default when performing database operations involving the entities.

MitigacionesMitigations

El comportamiento anterior a la versión 3.0 se puede restaurar mediante la configuración del modo de acceso de propiedad en ModelBuilder.The pre-3.0 behavior can be restored through configuration of the property access mode on ModelBuilder. Por ejemplo:For example:

modelBuilder.UsePropertyAccessMode(PropertyAccessMode.PreferFieldDuringConstruction);

Inicio de excepciones si se encuentran varios campos de respaldo compatiblesThrow if multiple compatible backing fields are found

Problema de seguimiento n.º 12523Tracking Issue #12523

Comportamiento anteriorOld behavior

Antes de EF Core 3.0, si varios campos coincidían con las reglas para buscar el campo de respaldo de una propiedad, se elegía un campo según un orden de prioridad.Before EF Core 3.0, if multiple fields matched the rules for finding the backing field of a property, then one field would be chosen based on some precedence order. Esto podía producir que, en caso de ambigüedad, se usara el campo incorrecto.This could cause the wrong field to be used in ambiguous cases.

Comportamiento nuevoNew behavior

A partir de EF Core 3.0, si varios campos coinciden con la misma propiedad, se inicia una excepción.Starting with EF Core 3.0, if multiple fields are matched to the same property, then an exception is thrown.

Por quéWhy

Este cambio se ha realizado para evitar de forma silenciosa el uso de un campo con respecto a otro cuando solo uno puede ser correcto.This change was made to avoid silently using one field over another when only one can be correct.

MitigacionesMitigations

En las propiedades con campos de respaldo ambiguos se debe especificar de forma explícita el campo que se va usar.Properties with ambiguous backing fields must have the field to use specified explicitly. Por ejemplo, con la API fluida:For example, using the fluent API:

modelBuilder
    .Entity<Blog>()
    .Property(e => e.Id)
    .HasField("_id");

Los nombres de propiedades de solo campo deben coincidir con el nombre del campoField-only property names should match the field name

Comportamiento anteriorOld behavior

Antes de EF Core 3.0, una propiedad podía especificarse con un valor de cadena y, si no había ninguna propiedad con ese nombre en el tipo .NET, EF Core intentaba hacerla coincidir con un campo mediante reglas de convención.Before EF Core 3.0, a property could be specified by a string value and if no property with that name was found on the .NET type then EF Core would try to match it to a field using convention rules.

private class Blog
{
    private int _id;
    public string Name { get; set; }
}
modelBuilder
    .Entity<Blog>()
    .Property("Id");

Comportamiento nuevoNew behavior

A partir de EF Core 3.0, una propiedad de solo campo debe coincidir exactamente con el nombre del campo.Starting with EF Core 3.0, a field-only property must match the field name exactly.

modelBuilder
    .Entity<Blog>()
    .Property("_id");

Por quéWhy

Este cambio se realizó para evitar el uso del mismo campo para dos propiedades con nombres similares. También hace que las reglas de coincidencia para propiedades solo de campo sean las mismas que para las propiedades asignadas a propiedades CLR.This change was made to avoid using the same field for two properties named similarly, it also makes the matching rules for field-only properties the same as for properties mapped to CLR properties.

MitigacionesMitigations

Las propiedades solo de campo deberían tener el mismo nombre que el campo al que están asignadas.Field-only properties must be named the same as the field they are mapped to. En una próxima versión de EF Core 3.0 tenemos planeado volver a habilitar la configuración explícita de un nombre de campo distinto al nombre de la propiedad (vea el problema n.° 15307):In a future release of EF Core after 3.0, we plan to re-enable explicitly configuring a field name that is different from the property name (see issue #15307):

modelBuilder
    .Entity<Blog>()
    .Property("Id")
    .HasField("_id");

AddDbContext/AddDbContextPool ya no llaman a AddLogging ni a AddMemoryCacheAddDbContext/AddDbContextPool no longer call AddLogging and AddMemoryCache

Problema de seguimiento n.° 14756Tracking Issue #14756

Comportamiento anteriorOld behavior

Antes de EF Core 3.0, llamar a AddDbContext o a AddDbContextPool también podría registrar los servicios de almacenamiento en caché y de registro con D.I. a través de llamadas a AddLogging y a AddMemoryCache.Before EF Core 3.0, calling AddDbContext or AddDbContextPool would also register logging and memory caching services with D.I through calls to AddLogging and AddMemoryCache.

Comportamiento nuevoNew behavior

A partir de EF Core 3.0, AddDbContext y AddDbContextPool ya no registrarán estos servicios con inserción de dependencias (DI).Starting with EF Core 3.0, AddDbContext and AddDbContextPool will no longer register these services with Dependency Injection (DI).

Por quéWhy

EF Core 3.0 no requiere que estos servicios estén en el contenedor de inserción de dependencias de la aplicación.EF Core 3.0 does not require that these services are in the application's DI container. Pero si ILoggerFactory se registra en el contenedor de DI de la aplicación, EF Core lo empezará a usar de todos modos.However, if ILoggerFactory is registered in the application's DI container, then it will still be used by EF Core.

MitigacionesMitigations

Si la aplicación necesita estos servicios, regístrelos de manera explícita con el contenedor de DI mediante AddLogging o AddMemoryCache.If your application needs these services, then register them explicitly with the DI container using AddLogging or AddMemoryCache.

Ahora DbContext.Entry realiza una operación DetectChanges localDbContext.Entry now performs a local DetectChanges

Problema de seguimiento n.º 13552Tracking Issue #13552

Comportamiento anteriorOld behavior

Antes de EF Core 3.0, la llamada a DbContext.Entry provocaba que se detectaran cambios para todas las entidades con seguimiento.Before EF Core 3.0, calling DbContext.Entry would cause changes to be detected for all tracked entities. Esto garantizaba que el estado expuesto en EntityEntry estuviera actualizado.This ensured that the state exposed in the EntityEntry was up-to-date.

Comportamiento nuevoNew behavior

A partir de EF Core 3.0, ahora la llamada a DbContext.Entry solo intenta detectar cambios en la entidad dada y cualquier entidad de seguridad relacionada con ella de la que se haya realizado el seguimiento.Starting with EF Core 3.0, calling DbContext.Entry will now only attempt to detect changes in the given entity and any tracked principal entities related to it. Esto significa que es posible que la llamada a este método no haya detectado otros cambios, lo que podría tener implicaciones en el estado de la aplicación.This means that changes elsewhere may not have been detected by calling this method, which could have implications on application state.

Observe que si ChangeTracker.AutoDetectChangesEnabled se establece en false incluso esta detección de cambios local se deshabilitará.Note that if ChangeTracker.AutoDetectChangesEnabled is set to false then even this local change detection will be disabled.

Otros métodos que provocan la detección de cambios (como ChangeTracker.Entries y SaveChanges) siguen provocando una acción DetectChanges completa de todas las entidades de las que se realiza el seguimiento.Other methods that cause change detection--for example ChangeTracker.Entries and SaveChanges--still cause a full DetectChanges of all tracked entities.

Por quéWhy

Este cambio se ha realizado para mejorar el rendimiento predeterminado del uso de context.Entry.This change was made to improve the default performance of using context.Entry.

MitigacionesMitigations

Llame a ChgangeTracker.DetectChanges() de forma explícita antes de llamar a Entry para garantizar el comportamiento anterior a la versión 3.0.Call ChgangeTracker.DetectChanges() explicitly before calling Entry to ensure the pre-3.0 behavior.

El cliente no genera las claves de matriz de cadena y byte de forma predeterminadaString and byte array keys are not client-generated by default

Problema de seguimiento n.º 14617Tracking Issue #14617

Comportamiento anteriorOld behavior

Antes de EF Core 3.0, se podían usar las propiedades de clave string y byte[] sin tener que establecer de forma explícita un valor distinto de NULL.Before EF Core 3.0, string and byte[] key properties could be used without explicitly setting a non-null value. En ese caso, el valor de clave se generaba en el cliente como un GUID, que se serializaba en bytes para byte[].In such a case, the key value would be generated on the client as a GUID, serialized to bytes for byte[].

Comportamiento nuevoNew behavior

A partir de EF Core 3.0, se iniciará una excepción en la que indica que no se ha establecido ningún valor de clave.Starting with EF Core 3.0 an exception will be thrown indicating that no key value has been set.

Por quéWhy

Este cambio se ha realizado porque los valores string/byte[] generados por el cliente no suelen ser útiles, y el comportamiento predeterminado dificultaba razonar sobre los valores de clave generados de una forma habitual.This change was made because client-generated string/byte[] values generally aren't useful, and the default behavior made it hard to reason about generated key values in a common way.

MitigacionesMitigations

Se puede obtener el comportamiento anterior a la versión 3.0 si se especifica de forma explícita que las propiedades de clave deben usar los valores generados si no se establece ningún otro valor distinto de NULL.The pre-3.0 behavior can be obtained by explicitly specifying that the key properties should use generated values if no other non-null value is set. Por ejemplo, con la API fluida:For example, with the fluent API:

modelBuilder
    .Entity<Blog>()
    .Property(e => e.Id)
    .ValueGeneratedOnAdd();

O bien con anotaciones de datos:Or with data annotations:

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }

Ahora ILoggerFactory es un servicio con ámbitoILoggerFactory is now a scoped service

Problema de seguimiento n.º 14698Tracking Issue #14698

Comportamiento anteriorOld behavior

Antes de EF Core 3.0, ILoggerFactory se registraba como un servicio de singleton.Before EF Core 3.0, ILoggerFactory was registered as a singleton service.

Comportamiento nuevoNew behavior

A partir de EF Core 3.0, ILoggerFactory ahora se registra como con ámbito.Starting with EF Core 3.0, ILoggerFactory is now registered as scoped.

Por quéWhy

Este cambio se ha realizado para permitir la asociación de un registrador con una instancia de DbContext, lo que habilita otras funciones y quita algunos casos de comportamiento patológico como un aumento vertiginoso de los proveedores de servicios internos.This change was made to allow association of a logger with a DbContext instance, which enables other functionality and removes some cases of pathological behavior such as an explosion of internal service providers.

MitigacionesMitigations

Este cambio no debería afectar al código de la aplicación a menos que registre y use servicios personalizados en el proveedor de servicios internos de EF Core.This change should not impact application code unless it is registering and using custom services on the EF Core internal service provider. Esto no es habitual.This isn't common. En estos casos, la mayoría de los elementos seguirá funcionando, pero cualquier servicio de singleton que dependiera de ILoggerFactory tendrá que cambiarse para obtener la interfaz ILoggerFactory de otra forma.In these cases, most things will still work, but any singleton service that was depending on ILoggerFactory will need to be changed to obtain the ILoggerFactory in a different way.

Si experimenta situaciones como esta, registre un problema en el rastreador de problemas de GitHub de EF Core para hacernos saber cómo usa ILoggerFactory, para que podamos comprender mejor cómo evitar esta interrupción en el futuro.If you run into situations like this, please file an issue at on the EF Core GitHub issue tracker to let us know how you are using ILoggerFactory such that we can better understand how not to break this again in the future.

En los proxies de carga diferida ya no se supone que las propiedades de navegación están totalmente cargadasLazy-loading proxies no longer assume navigation properties are fully loaded

Problema de seguimiento n.º 12780Tracking Issue #12780

Comportamiento anteriorOld behavior

Antes de EF Core 3.0, una vez que se eliminaba DbContext no había ninguna forma de saber si una determinada propiedad de navegación de una entidad obtenida de ese contexto se había cargado completamente o no.Before EF Core 3.0, once a DbContext was disposed there was no way of knowing if a given navigation property on an entity obtained from that context was fully loaded or not. En su lugar, los proxies asumían que una navegación de referencia se cargaba si tenía un valor distinto de NULL, y que una navegación de colección se cargaba si no estaba vacía.Proxies would instead assume that a reference navigation is loaded if it has a non-null value, and that a collection navigation is loaded if it isn't empty. En estos casos, el intento de carga diferida era no operativo.In these cases, attempting to lazy-load would be a no-op.

Comportamiento nuevoNew behavior

A partir de EF Core 3.0, los proxies realizan el seguimiento de si una propiedad de navegación se carga o no.Starting with EF Core 3.0, proxies keep track of whether or not a navigation property is loaded. Esto significa que el intento de acceder a una propiedad de navegación que se carga después de que se haya eliminado el contexto siempre será no operativo, incluso cuando la navegación cargada está vacía o es NULL.This means attempting to access a navigation property that is loaded after the context has been disposed will always be a no-op, even when the loaded navigation is empty or null. Por el contrario, el intento de acceder a una propiedad de navegación que no está cargada iniciará una excepción si el contexto se ha eliminado, incluso si la propiedad de navegación es una colección no vacía.Conversely, attempting to access a navigation property that isn't loaded will throw an exception if the context is disposed even if the navigation property is a non-empty collection. Si se produce esta situación, significa que el código de aplicación está intentando usar la carga diferida en un momento no válido y que se debe cambiar la aplicación para que lo no haga.If this situation arises, it means the application code is attempting to use lazy-loading at an invalid time, and the application should be changed to not do this.

Por quéWhy

Este cambio se ha realizado para que el comportamiento sea coherente y correcto cuando se intenta la carga diferida de una instancia de DbContext eliminada.This change was made to make the behavior consistent and correct when attempting to lazy-load on a disposed DbContext instance.

MitigacionesMitigations

Actualice el código de la aplicación para que no intente la carga diferida con un contexto eliminado, o bien configúrelo para que sea no operativo, como se describe en el mensaje de la excepción.Update application code to not attempt lazy-loading with a disposed context, or configure this to be a no-op as described in the exception message.

La creación excesiva de proveedores de servicios internos ahora es un error de forma predeterminadaExcessive creation of internal service providers is now an error by default

Problema de seguimiento n.º 10236Tracking Issue #10236

Comportamiento anteriorOld behavior

Antes de EF Core 3.0, se registraba una advertencia para una aplicación que creaba un número patológico de proveedores de servicios internos.Before EF Core 3.0, a warning would be logged for an application creating a pathological number of internal service providers.

Comportamiento nuevoNew behavior

A partir de EF Core 3.0, ahora esta advertencia se considera un error y se inicia una excepción.Starting with EF Core 3.0, this warning is now considered and error and an exception is thrown.

Por quéWhy

Este cambio se ha realizado para controlar mejor el código de la aplicación mediante la exposición de este caso patológico de una forma más explícita.This change was made to drive better application code through exposing this pathological case more explicitly.

MitigacionesMitigations

Cuando se produce este error, la acción más adecuada consiste en comprender la causa raíz y detener la creación de tantos proveedores de servicios internos.The most appropriate cause of action on encountering this error is to understand the root cause and stop creating so many internal service providers. Pero el error se puede convertir en una advertencia (u omitirse) mediante configuración en DbContextOptionsBuilder.However, the error can be converted back to a warning (or ignored) via configuration on the DbContextOptionsBuilder. Por ejemplo:For example:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder
        .ConfigureWarnings(w => w.Log(CoreEventId.ManyServiceProvidersCreatedWarning));
}

Comportamiento nuevo de HasOne/HasMany llamado con una sola cadenaNew behavior for HasOne/HasMany called with a single string

Problema de seguimiento n.° 9171Tracking Issue #9171

Comportamiento anteriorOld behavior

Antes de EF Core 3.0, el código para llamar a HasOne o HasMany con una cadena se interpretaba de manera confusa.Before EF Core 3.0, code calling HasOne or HasMany with a single string was interpreted in a confusing way. Por ejemplo:For example:

modelBuilder.Entity<Samurai>().HasOne("Entrance").WithOne();

El código parece relacionar Samurai con otro tipo de entidad mediante la propiedad de navegación Entrance, que puede ser privada.The code looks like it is relating Samurai to some other entity type using the Entrance navigation property, which may be private.

En realidad, este código intenta crear una relación con algún tipo de entidad denominada Entrance sin ninguna propiedad de navegación.In reality, this code attempts to create a relationship to some entity type called Entrance with no navigation property.

Comportamiento nuevoNew behavior

A partir de EF Core 3.0, el código anterior ahora hace lo que parecía que debía hacer antes.Starting with EF Core 3.0, the code above now does what it looked like it should have been doing before.

Por quéWhy

El comportamiento anterior era muy confuso, especialmente al leer el código de configuración y al buscar errores.The old behavior was very confusing, especially when reading the configuration code and looking for errors.

MitigacionesMitigations

Esto solo interrumpirá las aplicaciones que configuran de manera explícita las relaciones con cadenas para nombres de tipos y sin especificar explícitamente la propiedad de navegación.This will only break applications that are explicitly configuring relationships using strings for type names and without specifying the navigation property explicitly. Esto no es habitual.This is not common. El comportamiento anterior se puede obtener al pasar de manera explícita null para el nombre de la propiedad de navegación.The previous behavior can be obtained through explicitly passing null for the navigation property name. Por ejemplo:For example:

modelBuilder.Entity<Samurai>().HasOne("Some.Entity.Type.Name", null).WithOne();

El tipo de valor devuelto para varios métodos asincrónicos se ha cambiado de Task a ValueTaskThe return type for several async methods has been changed from Task to ValueTask

Problema de seguimiento n.º 15184Tracking Issue #15184

Comportamiento anteriorOld behavior

Antes, los siguientes métodos asincrónicos devolvían Task<T>:The following async methods previously returned a Task<T>:

  • DbContext.FindAsync()
  • DbSet.FindAsync()
  • DbContext.AddAsync()
  • DbSet.AddAsync()
  • ValueGenerator.NextValueAsync() (y las clases derivadas)ValueGenerator.NextValueAsync() (and deriving classes)

Comportamiento nuevoNew behavior

Dichos métodos ahora devuelven ValueTask<T> durante el mismo T que antes.The aforementioned methods now return a ValueTask<T> over the same T as before.

Por quéWhy

Este cambio reduce el número de asignaciones de montones que se producen al invocar estos métodos, lo que mejora el rendimiento general.This change reduces the number of heap allocations incurred when invoking these methods, improving general performance.

MitigacionesMitigations

Las aplicaciones que simplemente esperen las API anteriores solo necesitan recompilarse, sin que sea necesario realizar cambios en el código fuente.Applications simply awaiting the above APIs only need to be recompiled - no source changes are necessary. Un uso más complejo (p. ej., pasar el valor Task devuelto a Task.WhenAny()) normalmente requiere que el valor ValueTask<T> devuelto se convierta en Task<T> mediante una llamada a AsTask() en él.A more complex usage (e.g. passing the returned Task to Task.WhenAny()) typically require that the returned ValueTask<T> be converted to a Task<T> by calling AsTask() on it. Tenga en cuenta que esto niega la reducción de asignación que implica este cambio.Note that this negates the allocation reduction that this change brings.

La anotación Relational:TypeMapping ahora es simplemente TypeMappingThe Relational:TypeMapping annotation is now just TypeMapping

Problema de seguimiento n.º 9913Tracking Issue #9913

Comportamiento anteriorOld behavior

El nombre de anotación para las anotaciones de asignación de tipos era "Relational:TypeMapping".The annotation name for type mapping annotations was "Relational:TypeMapping".

Comportamiento nuevoNew behavior

Ahora, el nombre de anotación para las anotaciones de asignación de tipos es "TypeMapping".The annotation name for type mapping annotations is now "TypeMapping".

Por quéWhy

Ahora, las asignaciones de tipos se usan para algo más que solo para proveedores de bases de datos relacionales.Type mappings are now used for more than just relational database providers.

MitigacionesMitigations

Esto solo interrumpirá a las aplicaciones que acceden directamente a la asignación de tipos como una anotación, lo que no es habitual.This will only break applications that access the type mapping directly as an annotation, which isn't common. La acción más apropiada para corregir es usar la superficie de API para acceder a las asignaciones de tipos en lugar de usar directamente la anotación.The most appropriate action to fix is to use API surface to access type mappings rather than using the annotation directly.

ToTable en un tipo derivado inicia una excepciónToTable on a derived type throws an exception

Problema de seguimiento n.º 11811Tracking Issue #11811

Comportamiento anteriorOld behavior

Antes de EF Core 3.0, la llamada a ToTable() en un tipo derivado se omitía, ya que la única estrategia asignación de herencia era TPH, lo que no es válido.Before EF Core 3.0, ToTable() called on a derived type would be ignored since only inheritance mapping strategy was TPH where this isn't valid.

Comportamiento nuevoNew behavior

A partir de EF Core 3.0, y en preparación para agregar compatibilidad con TPT y TPC en una versión posterior, ahora la llamada a ToTable() en un tipo derivado iniciará una excepción para evitar un cambio de asignación inesperado en el futuro.Starting with EF Core 3.0 and in preparation for adding TPT and TPC support in a later release, ToTable() called on a derived type will now throw an exception to avoid an unexpected mapping change in the future.

Por quéWhy

En la actualidad no se considera válido asignar un tipo derivado a otra tabla.Currently it isn't valid to map a derived type to a different table. Este cambio evita interrupciones en el futuro, cuando se convierta en una operación válida.This change avoids breaking in the future when it becomes a valid thing to do.

MitigacionesMitigations

Quite todos los intentos de asignar tipos derivados a otras tablas.Remove any attempts to map derived types to other tables.

ForSqlServerHasIndex se ha reemplazado por HasIndexForSqlServerHasIndex replaced with HasIndex

Problema de seguimiento n.º 12366Tracking Issue #12366

Comportamiento anteriorOld behavior

Antes de EF Core 3.0, ForSqlServerHasIndex().ForSqlServerInclude() proporcionaba una manera de configurar las columnas que se usaban con INCLUDE.Before EF Core 3.0, ForSqlServerHasIndex().ForSqlServerInclude() provided a way to configure columns used with INCLUDE.

Comportamiento nuevoNew behavior

A partir de EF Core 3.0, ya se admite el uso de Include en un índice en el nivel relacional.Starting with EF Core 3.0, using Include on an index is now supported at the relational level. Use HasIndex().ForSqlServerInclude().Use HasIndex().ForSqlServerInclude().

Por quéWhy

Este cambio se ha realizado para consolidar la API para índices con Include en un mismo lugar para todos los proveedores de base de datos.This change was made to consolidate the API for indexes with Include into one place for all database providers.

MitigacionesMitigations

Use la API nueva, como se ha mostrado anteriormente.Use the new API, as shown above.

Cambios en la API de metadatosMetadata API changes

Problema de seguimiento n.º 214Tracking Issue #214

Comportamiento nuevoNew behavior

Las siguientes propiedades se han convertido en métodos de extensión:The following properties were converted to extension methods:

  • IEntityType.QueryFilter -> GetQueryFilter()
  • IEntityType.DefiningQuery -> GetDefiningQuery()
  • IProperty.IsShadowProperty -> IsShadowProperty()
  • IProperty.BeforeSaveBehavior -> GetBeforeSaveBehavior()
  • IProperty.AfterSaveBehavior -> GetAfterSaveBehavior()

Por quéWhy

Este cambio simplifica la implementación de las interfaces mencionadas anteriormente.This change simplifies the implementation of the aforementioned interfaces.

MitigacionesMitigations

Use los nuevos métodos de extensión.Use the new extension methods.

Cambios en la API de metadatos específicos del proveedorProvider-specific Metadata API changes

Problema de seguimiento n.º 214Tracking Issue #214

Comportamiento nuevoNew behavior

Los métodos de extensión específicos del proveedor se simplificarán:The provider-specific extension methods will be flattened out:

  • IProperty.Relational().ColumnName -> IProperty.GetColumnName()
  • IEntityType.SqlServer().IsMemoryOptimized -> IEntityType.IsMemoryOptimized()
  • PropertyBuilder.UseSqlServerIdentityColumn() -> PropertyBuilder.UseIdentityColumn()

Por quéWhy

Este cambio simplifica la implementación de los métodos de extensión mencionados anteriormente.This change simplifies the implementation of the aforementioned extension methods.

MitigacionesMitigations

Use los nuevos métodos de extensión.Use the new extension methods.

EF Core ya no envía pragma para el cumplimiento de SQLite FKEF Core no longer sends pragma for SQLite FK enforcement

Problema de seguimiento n.º 12151Tracking Issue #12151

Comportamiento anteriorOld behavior

Antes de EF Core 3.0, EF Core enviaba PRAGMA foreign_keys = 1 cuando se abría una conexión con SQLite.Before EF Core 3.0, EF Core would send PRAGMA foreign_keys = 1 when a connection to SQLite is opened.

Comportamiento nuevoNew behavior

A partir de EF Core 3.0, EF Core ya no envía PRAGMA foreign_keys = 1 cuando se abre una conexión con SQLite.Starting with EF Core 3.0, EF Core no longer sends PRAGMA foreign_keys = 1 when a connection to SQLite is opened.

Por quéWhy

Este cambio se ha realizado porque en EF Core se usa SQLitePCLRaw.bundle_e_sqlite3 de forma predeterminada, lo que a su vez significa que el cumplimiento de CD está activado de forma predeterminada y no es necesario habilitarlo explícitamente cada vez que se abra una conexión.This change was made because EF Core uses SQLitePCLRaw.bundle_e_sqlite3 by default, which in turn means that FK enforcement is switched on by default and doesn't need to be explicitly enabled each time a connection is opened.

MitigacionesMitigations

Las claves externas se habilitan de forma predeterminada en SQLitePCLRaw.bundle_e_sqlite3, que en EF Core se usa de forma predeterminada.Foreign keys are enabled by default in SQLitePCLRaw.bundle_e_sqlite3, which is used by default for EF Core. Para otros casos, las claves externas se pueden habilitar mediante la especificación de Foreign Keys=True en la cadena de conexión.For other cases, foreign keys can be enabled by specifying Foreign Keys=True in your connection string.

Microsoft.EntityFrameworkCore.Sqlite ahora depende de SQLitePCLRaw.bundle_e_sqlite3Microsoft.EntityFrameworkCore.Sqlite now depends on SQLitePCLRaw.bundle_e_sqlite3

Comportamiento anteriorOld behavior

Antes de EF Core 3.0, en EF Core se usaba SQLitePCLRaw.bundle_green.Before EF Core 3.0, EF Core used SQLitePCLRaw.bundle_green.

Comportamiento nuevoNew behavior

A partir de EF Core 3.0, en EF Core se usa SQLitePCLRaw.bundle_e_sqlite3.Starting with EF Core 3.0, EF Core uses SQLitePCLRaw.bundle_e_sqlite3.

Por quéWhy

Este cambio se ha realizado para que la versión de SQLite que se usa en iOS sea coherente con otras plataformas.This change was made so that the version of SQLite used on iOS consistent with other platforms.

MitigacionesMitigations

Para usar la versión nativa de SQLite en iOS, configure Microsoft.Data.Sqlite para usar otra agrupación SQLitePCLRaw.To use the native SQLite version on iOS, configure Microsoft.Data.Sqlite to use a different SQLitePCLRaw bundle.

Almacenamiento de valores GUID como TEXT en SQLiteGuid values are now stored as TEXT on SQLite

Problema de seguimiento n.º 15078Tracking Issue #15078

Comportamiento anteriorOld behavior

Antes, los valores GUID se almacenaban como valores BLOB en SQLite.Guid values were previously stored as BLOB values on SQLite.

Comportamiento nuevoNew behavior

Ahora, los valores GUID se almacenan como TEXT.Guid values are now stored as TEXT.

Por quéWhy

El formato binario de los GUID no está normalizado.The binary format of Guids is not standardized. El almacenamiento de los valores como TEXT mejora la compatibilidad de la base de datos con otras tecnologías.Storing the values as TEXT makes the database more compatible with other technologies.

MitigacionesMitigations

Puede migrar las bases de datos existentes al nuevo formato ejecutando SQL de la siguiente forma.You can migrate existing databases to the new format by executing SQL like the following.

UPDATE MyTable
SET GuidColumn = hex(substr(GuidColumn, 4, 1)) ||
                 hex(substr(GuidColumn, 3, 1)) ||
                 hex(substr(GuidColumn, 2, 1)) ||
                 hex(substr(GuidColumn, 1, 1)) || '-' ||
                 hex(substr(GuidColumn, 6, 1)) ||
                 hex(substr(GuidColumn, 5, 1)) || '-' ||
                 hex(substr(GuidColumn, 8, 1)) ||
                 hex(substr(GuidColumn, 7, 1)) || '-' ||
                 hex(substr(GuidColumn, 9, 2)) || '-' ||
                 hex(substr(GuidColumn, 11, 6))
WHERE typeof(GuidColumn) == 'blob';

En EF Core, también puede seguir usando el comportamiento anterior configurando un convertidor de valores en estas propiedades.In EF Core, you could also continue using the previous behavior by configuring a value converter on these properties.

modelBuilder
    .Entity<MyEntity>()
    .Property(e => e.GuidProperty)
    .HasConversion(
        g => g.ToByteArray(),
        b => new Guid(b));

Microsoft.Data.Sqlite sigue siendo capaz de leer valores GUID de ambas columnas BLOB y TEXT. Sin embargo, dado que el formato predeterminado de los parámetros y las constantes ha cambiado, seguramente deberá realizar alguna acción en la mayoría de casos que impliquen el uso de valores GUID.Microsoft.Data.Sqlite remains capable of reading Guid values from both BLOB and TEXT columns; however, since the default format for parameters and constants has changed you'll likely need to take action for most scenarios involving Guids.

Ahora los valores char se almacenan como TEXT en SQLiteChar values are now stored as TEXT on SQLite

Problema de seguimiento n.º 15020Tracking Issue #15020

Comportamiento anteriorOld behavior

Anteriormente los valores char se almacenaban como valores INTEGER en SQLite.Char values were previously sored as INTEGER values on SQLite. Por ejemplo, un valor char de A se almacenaba como el valor entero 65.For example, a char value of A was stored as the integer value 65.

Comportamiento nuevoNew behavior

Ahora, los valores char se almacenan como TEXT.Char values are now stored as TEXT.

Por quéWhy

El almacenamiento de valores como TEXT es más natural y mejora la compatibilidad de la base de datos con otras tecnologías.Storing the values as TEXT is more natural and makes the database more compatible with other technologies.

MitigacionesMitigations

Puede migrar las bases de datos existentes al nuevo formato ejecutando SQL de la siguiente forma.You can migrate existing databases to the new format by executing SQL like the following.

UPDATE MyTable
SET CharColumn = char(CharColumn)
WHERE typeof(CharColumn) = 'integer';

En EF Core, también puede seguir usando el comportamiento anterior configurando un convertidor de valores en estas propiedades.In EF Core, you could also continue using the previous behavior by configuring a value converter on these properties.

modelBuilder
    .Entity<MyEntity>()
    .Property(e => e.CharProperty)
    .HasConversion(
        c => (long)c,
        i => (char)i);

Microsoft.Data.Sqlite también puede leer valores de caracteres tanto de columnas INTEGER como de columnas TEXT, por lo que es posible que no deba hacer nada dependiendo de su caso.Microsoft.Data.Sqlite also remains capable of reading character values from both INTEGER and TEXT columns, so certain scenarios may not require any action.

Ahora los id. de migración se generan usando el calendario de la referencia cultural invariableMigration IDs are now generated using the invariant culture's calendar

Problema de seguimiento n.º 12978Tracking Issue #12978

Comportamiento anteriorOld behavior

Los identificadores de migración se generaban de forma involuntaria con el calendario de la referencia cultural actual.Migration IDs were inadvertently generated using the current culture's calendar.

Comportamiento nuevoNew behavior

Ahora los id. de migración siempre se generan usando el calendario de la referencia cultural invariable (gregoriano).Migration IDs are now always generated using the invariant culture's calendar (Gregorian).

Por quéWhy

El orden de las migraciones es importante al actualizar la base de datos o al solucionar conflictos de combinación.The order of migrations is important when updating the database or resolving merge conflicts. Al usar el calendario invariable, se evitan problemas de ordenación que pueden producirse si los miembros del equipo tienen distintos calendarios del sistema.Using the invariant calendar avoids ordering issues that can result from team members having different system calendars.

MitigacionesMitigations

Esta cambio afecta a todas las personas que usan un calendario no gregoriano en el que el año sea superior al del calendario gregoriano (como el calendario budista tailandés).This change affects anyone using a non-Gregorian calendar where the year is greater than the Gregorian calendar (like the Thai Buddhist calendar). Los id. de migración existentes deberán actualizarse para que las migraciones nuevas se ordenen después de las existentes.Existing migration IDs will need to be updated so that new migrations are ordered after existing migrations.

Puede ver el id. de migración en el atributo Migration de los archivos de diseñador de la migración.The migration ID can be found in the Migration attribute in the migrations' designer files.

 [DbContext(typeof(MyDbContext))]
-[Migration("25620318122820_MyMigration")]
+[Migration("20190318122820_MyMigration")]
 partial class MyMigration
 {

También debe actualizarse la tabla de historial de migraciones.The Migrations history table also needs to be updated.

UPDATE __EFMigrationsHistory
SET MigrationId = CONCAT(LEFT(MigrationId, 4)  - 543, SUBSTRING(MigrationId, 4, 150))

Se ha quitado el elemento UseRowNumberForPagingUseRowNumberForPaging has been removed

Problema de seguimiento n.º 16400Tracking Issue #16400

Comportamiento anteriorOld behavior

Antes de EF Core 3.0, UseRowNumberForPaging se podía usar para generar SQL para la paginación de forma que fuera compatible con SQL Server 2008.Before EF Core 3.0, UseRowNumberForPaging could be used to generate SQL for paging that is compatible with SQL Server 2008.

Comportamiento nuevoNew behavior

A partir de EF Core 3.0, EF solo genera SQL para la paginación que únicamente es compatible con las versiones posteriores de SQL Server.Starting with EF Core 3.0, EF will only generate SQL for paging that is only compatible with later SQL Server versions.

Por quéWhy

El motivo de este cambio es que SQL Server 2008 ya no se admite. Además, la actualización de esta característica para que funcionase con los cambios en las consultas implementados en EF Core 3.0 llevaría mucho trabajo.We are making this change because SQL Server 2008 is no longer a supported product and updating this feature to work with the query changes made in EF Core 3.0 is significant work.

MitigacionesMitigations

Se recomienda actualizar a una versión más reciente de SQL Server, o bien utilizar un nivel de compatibilidad superior, de modo que el SQL que se genere se admita.We recommend updating to a newer version of SQL Server, or using a higher compatibility level, so that the generated SQL is supported. Dicho esto, si no puede hacerlo, escriba un comentario en el problema de seguimiento con los detalles al respecto.That being said, if you are unable to do this, then please comment on the tracking issue with details. En función de los comentarios, es posible que volvamos a valorar esta decisión.We may revisit this decision based on feedback.

La información o metadatos de la extensión se han quitado de IDbContextOptionsExtensionExtension info/metadata has been removed from IDbContextOptionsExtension

Problema de seguimiento n.º 16119Tracking Issue #16119

Comportamiento anteriorOld behavior

IDbContextOptionsExtension incluía métodos para proporcionar metadatos sobre la extensión.IDbContextOptionsExtension contained methods for providing metadata about the extension.

Comportamiento nuevoNew behavior

Estos métodos se han movido a una nueva clase base abstracta DbContextOptionsExtensionInfo, que se devuelve desde una nueva propiedad IDbContextOptionsExtension.Info.These methods have been moved onto a new DbContextOptionsExtensionInfo abstract base class, which is returned from a new IDbContextOptionsExtension.Info property.

Por quéWhy

Al lanzarse las versiones 2.0 y 3.0, tuvimos que agregar o cambiar estos métodos varias veces.Over the releases from 2.0 to 3.0 we needed to add to or change these methods several times. Su división en una nueva clase base abstracta facilitará la realización de este tipo de cambios sin interrumpir las extensiones existentes.Breaking them out into a new abstract base class will make it easier to make these kind of changes without breaking existing extensions.

MitigacionesMitigations

Actualice las extensiones para seguir el nuevo patrón.Update extensions to follow the new pattern. Encontrará ejemplos en las muchas implementaciones de IDbContextOptionsExtension para los diferentes tipos de extensiones en el código fuente de EF Core.Examples are found in the many implementations of IDbContextOptionsExtension for different kinds of extensions in the EF Core source code.

Cambio de nombre de LogQueryPossibleExceptionWithAggregateOperatorLogQueryPossibleExceptionWithAggregateOperator has been renamed

Problema de seguimiento n.º 10985Tracking Issue #10985

CambioChange

Se ha cambiado el nombre de RelationalEventId.LogQueryPossibleExceptionWithAggregateOperator a RelationalEventId.LogQueryPossibleExceptionWithAggregateOperatorWarning.RelationalEventId.LogQueryPossibleExceptionWithAggregateOperator has been renamed to RelationalEventId.LogQueryPossibleExceptionWithAggregateOperatorWarning.

Por quéWhy

Conviene alinear el nombre de este evento de advertencia con el del resto de eventos de advertencia.Aligns the naming of this warning event with all other warning events.

MitigacionesMitigations

Use el nuevo nombre.Use the new name. (Tenga en cuenta que el número de id. evento sigue siendo el mismo).(Note that the event ID number has not changed.)

Clarificación de la API para nombres de restricciones de claves externasClarify API for foreign key constraint names

Problema de seguimiento n.º 10730Tracking Issue #10730

Comportamiento anteriorOld behavior

Antes de EF Core 3.0, se utilizaba simplemente el término "nombre" para hacer referencia a los nombres de las restricciones de claves externas.Before EF Core 3.0, foreign key constraint names were referred to as simply the "name". Por ejemplo:For example:

var constraintName = myForeignKey.Name;

Comportamiento nuevoNew behavior

A partir de EF Core 3.0, el término con el que se hace referencia a los nombres de las restricciones de claves externas es "nombre de la restricción".Starting with EF Core 3.0, foreign key constraint names are now referred to as the "constraint name". Por ejemplo:For example:

var constraintName = myForeignKey.ConstraintName;

Por quéWhy

Este cambio permite mejorar la coherencia relativa a la nomenclatura en este aspecto y aclarar que se trata del nombre de una restricción de clave externa, y no del de la columna o propiedad en la que está definida la clave externa.This change brings consistency to naming in this area, and also clarifies that this is the name of the foreign key constraint, and not the column or property name that the foreign key is defined on.

MitigacionesMitigations

Use el nuevo nombre.Use the new name.

IRelationalDatabaseCreator.HasTables/HasTablesAsync se han hecho públicosIRelationalDatabaseCreator.HasTables/HasTablesAsync have been made public

Problema de seguimiento n.° 15997Tracking Issue #15997

Comportamiento anteriorOld behavior

Antes de EF Core 3.0, estos métodos estaban protegidos.Before EF Core 3.0, these methods were protected.

Comportamiento nuevoNew behavior

Desde EF Core 3.0, estos métodos son públicos.Starting with EF Core 3.0, these methods are public.

Por quéWhy

EF usa estos métodos para determinar si se ha creado una base de datos, pero está vacía.These methods are used by EF to determine if a database is created but empty. Esto también puede resultar útil fuera de EF al determinar si se deben aplicar migraciones o no.This can also be useful from outside EF when determining whether or not to apply migrations.

MitigacionesMitigations

Cambie la accesibilidad de cualquier invalidación.Change the accessibility of any overrides.

Microsoft.EntityFrameworkCore.Design es ahora un paquete DevelopmentDependencyMicrosoft.EntityFrameworkCore.Design is now a DevelopmentDependency package

Problema de seguimiento n.° 11506Tracking Issue #11506

Comportamiento anteriorOld behavior

Antes de EF Core 3.0, Microsoft.EntityFrameworkCore.Design era un paquete NuGet regular con un ensamblado al que podían hacer referencia los proyectos que dependían de él.Before EF Core 3.0, Microsoft.EntityFrameworkCore.Design was a regular NuGet package whose assembly could be referenced by projects that depended on it.

Comportamiento nuevoNew behavior

Desde EF Core 3.0, es un paquete DevelopmentDependency.Starting with EF Core 3.0, it is a DevelopmentDependency package. Esto significa que la dependencia no fluirá de manera transitiva en otros proyectos y que ya no puede, de forma predeterminada, hacer referencia a su ensamblado.Which means that the dependency won't flow transitively into other projects, and that you can no longer, by default, reference its assembly.

Por quéWhy

Este paquete solo está destinado a usarse en tiempo de diseño.This package is only intended to be used at design time. Las aplicaciones implementadas no deben hacer referencia al mismo.Deployed applications shouldn't reference it. Hacer que el paquete sea DevelopmentDependency refuerza esta recomendación.Making the package a DevelopmentDependency reinforces this recommendation.

MitigacionesMitigations

Si tiene que hacer referencia a este paquete para invalidar el comportamiento en tiempo de diseño de EF Core, puede actualizar los metadatos de elementos PackageReference del proyecto.If you need to reference this package to override EF Core's design-time behavior, you can update update PackageReference item metadata in your project. Si se hace referencia al paquete de manera transitiva a través de Microsoft.EntityFrameworkCore.Tools, tendrá que agregar una PackageReference explícita al paquete para cambiar sus metadatos.If the package is being referenced transitively via Microsoft.EntityFrameworkCore.Tools, you will need to add an explicit PackageReference to the package to change its metadata.

<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.0.0">
  <PrivateAssets>all</PrivateAssets>
  <!-- Remove IncludeAssets to allow compiling against the assembly -->
  <!--<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>-->
</PackageReference>

SQLitePCL.raw se ha actualizado a la versión 2.0.0SQLitePCL.raw updated to version 2.0.0

Problema de seguimiento n.° 14824Tracking Issue #14824

Comportamiento anteriorOld behavior

Microsoft.EntityFrameworkCore.Sqlite dependía anteriormente de la versión 1.1.12 de SQLitePCL.raw.Microsoft.EntityFrameworkCore.Sqlite previously depended on version 1.1.12 of SQLitePCL.raw.

Comportamiento nuevoNew behavior

Hemos actualizado nuestro paquete para depender de la versión 2.0.0.We've updated our package to depend on version 2.0.0.

Por quéWhy

La versión 2.0.0 de SQLitePCL.raw selecciona .NET Standard 2.0 como destino.Version 2.0.0 of SQLitePCL.raw targets .NET Standard 2.0. Anteriormente seleccionaba .NET Standard 1.1 como destino, que requería el cierre a gran escala de paquetes transitivos para su funcionamiento.It previously targeted .NET Standard 1.1 which required a large closure of transitive packages to work.

MitigacionesMitigations

En la versión 2.0.0 de SQLitePCL.raw se incluyen algunos cambios importantes.SQLitePCL.raw version 2.0.0 includes some breaking changes. Consulte las notas de la versión para obtener detalles.See the release notes for details.

NetTopologySuite se actualizó a la versión 2.0.0NetTopologySuite updated to version 2.0.0

Problema de seguimiento n.° 14825Tracking Issue #14825

Comportamiento anteriorOld behavior

Los paquetes espaciales anteriormente dependían de la versión 1.15.1 de NetTopologySuite.The spatial packages previously depended on version 1.15.1 of NetTopologySuite.

Comportamiento nuevoNew behavior

Hemos actualizado nuestro paquete para depender de la versión 2.0.0.We've update our package to depend on version 2.0.0.

Por quéWhy

La versión 2.0.0 de NetTopologySuite pretende resolver varios problemas de usabilidad que encontraron los usuarios de EF Core.Version 2.0.0 of NetTopologySuite aims to address several usability issues encountered by EF Core users.

MitigacionesMitigations

En la versión 2.0.0 de NetTopologySuite se incluyen algunos cambios importantes.NetTopologySuite version 2.0.0 includes some breaking changes. Consulte las notas de la versión para obtener detalles.See the release notes for details.

Se usa Microsoft.Data.SqlClient en lugar de System.Data.SqlClientMicrosoft.Data.SqlClient is used instead of System.Data.SqlClient

Problema de seguimiento n.º 15636Tracking Issue #15636

Comportamiento anteriorOld behavior

Microsoft.EntityFrameworkCore.SqlServer dependía anteriormente de la versión System.Data.SqlClient.Microsoft.EntityFrameworkCore.SqlServer previously depended on System.Data.SqlClient.

Comportamiento nuevoNew behavior

Hemos actualizado nuestro paquete para que dependa de Microsoft.Data.SqlClient.We've updated our package to depend on Microsoft.Data.SqlClient.

Por quéWhy

A partir de ahora, Microsoft.Data.SqlClient es el controlador de acceso a datos insignia para SQL Server y System.Data.SqlClient ya no es el centro de desarrollo.Microsoft.Data.SqlClient is the flagship data access driver for SQL Server going forward, and System.Data.SqlClient no longer be the focus of development. Algunas características importantes, como Always Encrypted, solo están disponibles en Microsoft.Data.SqlClient.Some important features, such as Always Encrypted, are only available on Microsoft.Data.SqlClient.

MitigacionesMitigations

Si el código toma una dependencia directa en System.Data.SqlClient, debe cambiarla para que haga referencia a Microsoft.Data.SqlClient en su lugar. Dado que los dos paquetes mantienen un grado muy alto de compatibilidad con la API, solo debería ser un paquete simple y un cambio de espacio de nombres.If your code takes a direct dependency on System.Data.SqlClient, you must change it to reference Microsoft.Data.SqlClient instead; as the two packages maintain a very high degree of API compatibility, this should only be a simple package and namespace change.

Se deben configurar varias relaciones de referencia automática ambiguasMultiple ambiguous self-referencing relationships must be configured

Problema de seguimiento n.º 13573Tracking Issue #13573

Comportamiento anteriorOld behavior

Un tipo de entidad con varias propiedades de navegación unidireccional de referencia automática y claves externas coincidentes se configuró incorrectamente como una única relación.An entity type with multiple self-referencing uni-directional navigation properties and matching FKs was incorrectly configured as a single relationship. Por ejemplo:For example:

public class User 
{
        public Guid Id { get; set; }
        public User CreatedBy { get; set; }
        public User UpdatedBy { get; set; }
        public Guid CreatedById { get; set; }
        public Guid? UpdatedById { get; set; }
}

Comportamiento nuevoNew behavior

Este escenario se detecta ahora en la generación del modelo y se produce una excepción que indica que el modelo es ambiguo.This scenario is now detected in model building and an exception is thrown indicating that the model is ambiguous.

Por quéWhy

El modelo resultante era ambiguo, y lo más probable es que sea incorrecto en este caso.The resultant model was ambiguous and will likely usually be wrong for this case.

MitigacionesMitigations

Utilice la configuración completa de la relación.Use full configuration of the relationship. Por ejemplo:For example:

modelBuilder
     .Entity<User>()
     .HasOne(e => e.CreatedBy)
     .WithMany();
 
 modelBuilder
     .Entity<User>()
     .HasOne(e => e.UpdatedBy)
     .WithMany();

DbFunction.Schema es NULL o la cadena vacía lo configura para estar en el esquema predeterminado del modeloDbFunction.Schema being null or empty string configures it to be in model's default schema

Problema de seguimiento n.º 12757Tracking Issue #12757

Comportamiento anteriorOld behavior

Una función DbFunction configurada con el esquema como una cadena vacía se trataba como una función integrada sin un esquema.A DbFunction configured with schema as an empty string was treated as built-in function without a schema. Por ejemplo, el código siguiente asignará la función CLR DatePart a la función integrada DATEPART en SqlServer.For example following code will map DatePart CLR function to DATEPART built-in function on SqlServer.

[DbFunction("DATEPART", Schema = "")]
public static int? DatePart(string datePartArg, DateTime? date) => throw new Exception();

Comportamiento nuevoNew behavior

Todas las asignaciones de DbFunction se consideran asignadas a funciones definidas por el usuario.All DbFunction mappings are considered to be mapped to user defined functions. Por lo tanto, el valor de cadena vacía colocaría la función dentro del esquema predeterminado del modelo,Hence empty string value would put the function inside the default schema for the model. que podría ser el esquema configurado de forma explícita mediante modelBuilder.HasDefaultSchema() de la API fluida o dbo en caso contrario.Which could be the schema configured explicitly via fluent API modelBuilder.HasDefaultSchema() or dbo otherwise.

Por quéWhy

Anteriormente, el esquema vacío era una manera de indicar que la función estaba integrada, pero esa lógica solo es aplicable a SqlServer, donde las funciones integradas no pertenecen a ningún esquema.Previously schema being empty was a way to treat that function is built-in but that logic is only applicable for SqlServer where built-in functions do not belong to any schema.

MitigacionesMitigations

Configure la traslación de DbFunction manualmente para asignarla a una función integrada.Configure DbFunction's translation manually to map it to a built-in function.

modelBuilder
    .HasDbFunction(typeof(MyContext).GetMethod(nameof(MyContext.DatePart)))
    .HasTranslation(args => SqlFunctionExpression.Create("DatePart", args, typeof(int?), null));