EF Core 3.0 中包含的重大變更Breaking changes included in EF Core 3.0

下列 API 和行為變更可能會在將現有的應用程式升級至3.0.0 時中斷。The following API and behavior changes have the potential to break existing applications when upgrading them to 3.0.0. 這些變更預期只會影響提供者變更底下記載的資料庫提供者。Changes that we expect to only impact database providers are documented under provider changes.

總結Summary

重大變更Breaking change 影響Impact
不會再於用戶端評估 LINQ 查詢LINQ queries are no longer evaluated on the client High
EF Core 3.0 以 .NET Standard 2.1 為目標,而非以 .NET Standard 2.0 為目標EF Core 3.0 targets .NET Standard 2.1 rather than .NET Standard 2.0 High
EF Core 命令列工具 dotnet ef 不再是 .NET Core SDK 的一部分The EF Core command-line tool, dotnet ef, is no longer part of the .NET Core SDK High
DetectChanges 接受存放區產生的索引鍵值DetectChanges honors store-generated key values High
FromSql、ExecuteSql 和 ExecuteSqlAsync 已重新命名FromSql, ExecuteSql, and ExecuteSqlAsync have been renamed High
查詢類型會與實體類型合併Query types are consolidated with entity types High
Entity Framework Core 不再屬於 ASP.NET Core 共用架構Entity Framework Core is no longer part of the ASP.NET Core shared framework Medium
現在預設會立即發生串聯刪除Cascade deletions now happen immediately by default Medium
相關實體的積極式載入現在會出現在單一查詢中Eager loading of related entities now happens in a single query Medium
DeleteBehavior.Restrict 具有更簡潔的語意DeleteBehavior.Restrict has cleaner semantics Medium
自有類型關聯性的設定 API 已變更Configuration API for owned type relationships has changed Medium
每個屬性會使用獨立的記憶體內部整數索引鍵產生Each property uses independent in-memory integer key generation Medium
無追蹤查詢已不再執行身分識別解析No-tracking queries no longer perform identity resolution Medium
中繼資料 API 變更Metadata API changes Medium
提供者獨有的中繼資料 API 變更Provider-specific Metadata API changes Medium
已移除 UseRowNumberForPagingUseRowNumberForPaging has been removed Medium
無法撰寫與預存程式搭配使用時的 FromSql 方法FromSql method when used with stored procedure cannot be composed Medium
FromSql 方法只能在查詢根目錄上指定FromSql methods can only be specified on query roots Low
查詢執行會在偵錯層級記錄已還原Query execution is logged at Debug level Reverted Low
實體執行個體上不會再設定暫存索引鍵值Temporary key values are no longer set onto entity instances Low
現在可選用以主體來共用資料表的相依實體Dependent entities sharing the table with the principal are now optional Low
共用具有並行語彙基元資料行的所有實體,都必須將其對應至屬性All entities sharing a table with a concurrency token column have to map it to a property Low
在沒有擁有者的情況下,無法使用追蹤查詢來查詢擁有的實體Owned entities cannot be queried without the owner using a tracking query Low
未對應類型的繼承屬性,現在會對應至所有衍生類型的單一資料行Inherited properties from unmapped types are now mapped to a single column for all derived types Low
外部索引鍵屬性慣例不會再比對與主體屬性相同的名稱The foreign key property convention no longer matches same name as the principal property Low
如果在 TransactionScope 完成之前未再使用,則資料庫連線現在已關閉Database connection is now closed if not used anymore before the TransactionScope has been completed Low
根據預設,會使用支援欄位Backing fields are used by default Low
找到多個相容的支援欄位時擲回Throw if multiple compatible backing fields are found Low
僅限欄位的屬性名稱應與欄位名稱相符Field-only property names should match the field name Low
AddDbContext/AddDbContextPool 再也不會呼叫 AddLogging 與 AddMemoryCacheAddDbContext/AddDbContextPool no longer call AddLogging and AddMemoryCache Low
AddEntityFramework * 新增具有大小限制的 IMemoryCacheAddEntityFramework* adds IMemoryCache with a size limit Low
DbContext.Entry 現在會執行本機 DetectChangesDbContext.Entry now performs a local DetectChanges Low
字串和位元組陣列索引鍵預設不是由用戶端產生String and byte array keys are not client-generated by default Low
ILoggerFactory 現在是限定範圍的服務ILoggerFactory is now a scoped service Low
消極式載入 Proxy 不再假設導覽屬性已完全載入Lazy-loading proxies no longer assume navigation properties are fully loaded Low
現在根據預設,過度建立內部服務提供者會是錯誤Excessive creation of internal service providers is now an error by default Low
使用單一字串呼叫之 HasOne/HasMany 的新行為New behavior for HasOne/HasMany called with a single string Low
數個非同步方法的傳回類型已從 Task 變更為 ValueTaskThe return type for several async methods has been changed from Task to ValueTask Low
Relational:TypeMapping 註解現在變成只有 TypeMappingThe Relational:TypeMapping annotation is now just TypeMapping Low
衍生類型上的 ToTable 會擲回例外狀況ToTable on a derived type throws an exception Low
EF Core 不會再傳送 SQLite FK 強制的 pragmaEF Core no longer sends pragma for SQLite FK enforcement Low
Microsoft.EntityFrameworkCore.Sqlite 現在相依於 SQLitePCLRaw.bundle_e_sqlite3Microsoft.EntityFrameworkCore.Sqlite now depends on SQLitePCLRaw.bundle_e_sqlite3 Low
GUID 值現在於 SQLite 上的儲存形式為 TEXTGuid values are now stored as TEXT on SQLite Low
Char 值現在於 SQLite 上會儲存為文字Char values are now stored as TEXT on SQLite Low
移轉識別碼現在會使用不因文化特性而異的行事曆產生Migration IDs are now generated using the invariant culture's calendar Low
已從 IDbContextOptionsExtension 移除延伸模組資訊/中繼資料Extension info/metadata has been removed from IDbContextOptionsExtension Low
已為 LogQueryPossibleExceptionWithAggregateOperator 重新命名LogQueryPossibleExceptionWithAggregateOperator has been renamed Low
讓 API 的外部索引鍵限制式名稱更清楚Clarify API for foreign key constraint names Low
IRelationalDatabaseCreator.HasTables/HasTablesAsync 已設為公用IRelationalDatabaseCreator.HasTables/HasTablesAsync have been made public Low
Microsoft.EntityFrameworkCore.Design 現在是 DevelopmentDependency 套件Microsoft.EntityFrameworkCore.Design is now a DevelopmentDependency package Low
SQLitePCL.raw 已更新為 2.0.0 版SQLitePCL.raw updated to version 2.0.0 Low
NetTopologySuite 已更新為 2.0.0 版NetTopologySuite updated to version 2.0.0 Low
SqlClient 是用來取代 SqlClient 的資料。Microsoft.Data.SqlClient is used instead of System.Data.SqlClient Low
必須設定多個不明確的自我參考關聯性Multiple ambiguous self-referencing relationships must be configured Low
DbFunction。架構為 null 或空字串,將其設定為模型的預設架構DbFunction.Schema being null or empty string configures it to be in model's default schema Low

不會再於用戶端評估 LINQ 查詢LINQ queries are no longer evaluated on the client

追蹤問題 #14935請參閱問題 #12795Tracking Issue #14935 Also see issue #12795

舊的行為Old behavior

3.0 以前,在 EF Core 無法將屬於查詢的運算式轉換成 SQL 或參數時,它會自動在用戶端評估運算式。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. 根據預設,對可能相當耗費資源的運算式進行用戶端評估只會觸發警告。By default, client evaluation of potentially expensive expressions only triggered a warning.

新的行為New behavior

從 3.0 開始,EF Core 只允許在用戶端評估最上層投影的運算式 (查詢中的最後一個 Select() 呼叫)。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. 當其他查詢部分中的運算式無法轉換成 SQL 或參數時,則會擲回例外狀況。When expressions in any other part of the query can't be converted to either SQL or a parameter, an exception is thrown.

因此Why

查詢的自動用戶端評估可執行許多查詢,即使無法轉譯查詢的重要部分也一樣。Automatic client evaluation of queries allows many queries to be executed even if important parts of them can't be translated. 此行為可能會導致非預期且可能造成傷害的行為,而且該行為可能只會出現在生產環境中。This behavior can result in unexpected and potentially damaging behavior that may only become evident in production. 例如,Where() 呼叫中無法轉譯的條件可能會導致資料表中的所有資料列從資料庫伺服器移轉,並在用戶端套用篩選。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. 如果資料表只包含幾個開發中的資料列,此情況可能很容易未被察覺;但當應用程式移至生產環境時,由於資料表可能包含數百萬個資料列,因此影響會很大。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. 用戶端評估警告也證明很容易在開發期間遭到忽略。Client evaluation warnings also proved too easy to ignore during development.

此外,自動用戶端評估可能會導致改善特定運算式的查詢轉譯造成版本間非預期的中斷性變更問題。Besides this, automatic client evaluation can lead to issues in which improving query translation for specific expressions caused unintended breaking changes between releases.

風險降低Mitigations

如果無法完整轉譯查詢,請以可轉譯的格式來重寫查詢,或是使用 AsEnumerable()ToList() 或類似函數來明確將資料帶回用戶端,以便接著使用 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 以 .NET Standard 2.1 為目標,而非以 .NET Standard 2.0 為目標EF Core 3.0 targets .NET Standard 2.1 rather than .NET Standard 2.0

追蹤問題 #15498Tracking Issue #15498

重要

EF Core 3.1 的目標 .NET Standard 2.0。EF Core 3.1 targets .NET Standard 2.0 again. 這會傳回 .NET Framework 的支援。This brings back support for .NET Framework.

舊的行為Old behavior

在 3.0 之前,EF Core 以 .NET Standard 2.0 為目標,且執行於支援該標準的所有平台上,包括 .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.

新的行為New behavior

從 3.0 開始,EF Core 以 .NET Standard 2.1 為目標,且執行於支援此標準的所有平台上。Starting with 3.0, EF Core targets .NET Standard 2.1 and will run on all platforms that support this standard. 這不包括 .NET Framework。This does not include .NET Framework.

因此Why

此為跨 .NET 技術的策略性決策之一部分,著重於 .NET Core 與其他現代化 .NET 平台 (例如 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.

風險降低Mitigations

使用 EF Core 3.1。Use EF Core 3.1.

Entity Framework Core 不再屬於 ASP.NET Core 共用架構Entity Framework Core is no longer part of the ASP.NET Core shared framework

追蹤問題公告 #325Tracking Issue Announcements#325

舊的行為Old behavior

在 ASP.NET Core 3.0 以前,當您新增 Microsoft.AspNetCore.AppMicrosoft.AspNetCore.All 的套件參考時,它會包含 EF Core 及部分 EF Core 資料提供者 (例如 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.

新的行為New behavior

從 3.0 開始,ASP.NET Core 共用架構不會包含 EF Core 或任何 EF Core 資料提供者。Starting in 3.0, the ASP.NET Core shared framework doesn't include EF Core or any EF Core data providers.

因此Why

在這項變更之前,取得 EF Core 會根據應用程式是否以 ASP.NET Core 和 SQL Server 為目標而需要不同的步驟。Before this change, getting EF Core required different steps depending on whether the application targeted ASP.NET Core and SQL Server or not. 此外,升級 ASP.NET Core 會強制升級 EF Core 和 SQL Server 提供者,這不一定符合需求。Also, upgrading ASP.NET Core forced the upgrade of EF Core and the SQL Server provider, which isn't always desirable.

透過這項變更,取得 EF Core 的體驗對所有提供者、支援的 .NET 實作和應用程式類型都相同。With this change, the experience of getting EF Core is the same across all providers, supported .NET implementations and application types. 開發人員現在也可以精確控制何時升級 EF Core 和 EF Core 資料提供者。Developers can also now control exactly when EF Core and EF Core data providers are upgraded.

風險降低Mitigations

若要在 ASP.NET Core 3.0 應用程式或其他支援的應用程式中使用 EF Core,請明確將套件參考加入應用程式會使用的 EF Core 資料庫提供者。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.

EF Core 命令列工具 dotnet ef 不再是 .NET Core SDK 的一部分The EF Core command-line tool, dotnet ef, is no longer part of the .NET Core SDK

追蹤問題 #14016Tracking Issue #14016

舊的行為Old behavior

在 3.0 之前,dotnet ef 工具包含在 .NET Core SDK,並可以輕易地從任何專案的命令列使用,而不需要額外步驟。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.

新的行為New behavior

從 3.0 開始,.NET SDK 不包含 dotnet ef 工具,因此您必須明確地將它安裝為本機或全域工具才能使用。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.

因此Why

這項變更可讓我們將 dotnet ef 當作 NuGet 上一般的 .NET CLI 工具來散發和更新,這點與 EF Core 3.0 一律當作 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.

風險降低Mitigations

若要能夠管理移轉或支撐 DbContext,請安裝 dotnet-ef 作為全域工具:To be able to manage migrations or scaffold a DbContext, install dotnet-ef as a global tool:

  $ dotnet tool install --global dotnet-ef

您也可以在還原專案相依性時取得它作為本機工具 (該專案是使用工具資訊清單檔將它宣告為工具相依性)。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 和 ExecuteSqlAsync 已重新命名FromSql, ExecuteSql, and ExecuteSqlAsync have been renamed

追蹤問題 #10996Tracking Issue #10996

舊的行為Old behavior

在 EF Core 3.0 之前,這些方法名稱已多載以使用一般字串,或應插入至 SQL 和參數的字串。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.

新的行為New behavior

從 EF Core 3.0 開始,請使用 FromSqlRawExecuteSqlRawExecuteSqlRawAsync 建立參數化查詢,其中參數會分別從查詢字串傳遞。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. 例如:For example:

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

使用 FromSqlInterpolatedExecuteSqlInterpolatedExecuteSqlInterpolatedAsync 建立參數化查詢,其中參數會作為插入查詢字串的一部分傳回。Use FromSqlInterpolated, ExecuteSqlInterpolated, and ExecuteSqlInterpolatedAsync to create a parameterized query where the parameters are passed as part of an interpolated query string. 例如:For example:

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

請注意,上述兩個查詢都會產生具有相同 SQL 參數的相同參數化 SQL。Note that both of the queries above will produce the same parameterized SQL with the same SQL parameters.

因此Why

像這樣的方法多載,使得原本要呼叫插入字串方法很容易意外呼叫原始字串方法,或反之。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. 這可能會導致查詢在應該參數化時不進行參數化。This could result in queries not being parameterized when they should have been.

風險降低Mitigations

切換至使用新的方法名稱。Switch to use the new method names.

無法撰寫與預存程式搭配使用時的 FromSql 方法FromSql method when used with stored procedure cannot be composed

追蹤問題 #15392Tracking Issue #15392

舊的行為Old behavior

在 EF Core 3.0 之前,FromSql 方法會嘗試偵測是否可以根據傳遞的 SQL 來進行撰寫。Before EF Core 3.0, FromSql method tried to detect if the passed SQL can be composed upon. 當 SQL 不是可組合的,如同預存程式,它會進行用戶端評估。It did client evaluation when the SQL was non-composable like a stored procedure. 下列查詢的運作方式是在伺服器上執行預存程式,並在用戶端上進行 FirstOrDefault。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();

新的行為New behavior

從 EF Core 3.0 開始,EF Core 不會嘗試剖析 SQL。Starting with EF Core 3.0, EF Core will not try to parse the SQL. 因此,如果您在 FromSqlRaw/FromSqlInterpolated 之後撰寫,則 EF Core 會藉由導致子查詢來撰寫 SQL。So if you are composing after FromSqlRaw/FromSqlInterpolated, then EF Core will compose the SQL by causing sub query. 因此,如果您使用具有組合的預存程式,則會收到無效 SQL 語法的例外狀況。So if you are using a stored procedure with composition then you will get an exception for invalid SQL syntax.

因此Why

EF Core 3.0 不支援自動用戶端評估,因為它容易發生錯誤,如這裡所述。EF Core 3.0 does not support automatic client evaluation, since it was error prone as explained here.

降低Mitigation

如果您使用 FromSqlRaw/FromSqlInterpolated 中的預存程式,您就知道它無法由撰寫,因此您可以在 FromSql 方法呼叫之後加入__enumerable.asenumerable/AsAsyncEnumerable__ ,以避免伺服器端上的任何組合。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();

FromSql 方法只能在查詢根目錄上指定FromSql methods can only be specified on query roots

追蹤問題 #15704Tracking Issue #15704

舊的行為Old behavior

在 EF Core 3.0 之前,可以在查詢中的任何位置指定 FromSql 方法。Before EF Core 3.0, the FromSql method could be specified anywhere in the query.

新的行為New behavior

從 EF Core 3.0 開始,新的 FromSqlRawFromSqlInterpolated 方法 (取代 FromSql) 只能在查詢根目錄上指定,亦即直接在 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<>. 嘗試在其他任何位置指定它們,將會導致編譯錯誤。Attempting to specify them anywhere else will result in a compilation error.

因此Why

DbSet 以外的任何地方指定 FromSql 沒有新增的意義或附加價值,而且在某些情況下可能會導致模稜兩可。Specifying FromSql anywhere other than on a DbSet had no added meaning or added value, and could cause ambiguity in certain scenarios.

風險降低Mitigations

FromSql 引動過程應該直接移至它們適用的 DbSetFromSql invocations should be moved to be directly on the DbSet to which they apply.

無追蹤查詢已不再執行身分識別解析No-tracking queries no longer perform identity resolution

追蹤問題 #13518Tracking Issue #13518

舊的行為Old behavior

在 EF Core 3.0 之前,每次出現具有給定類型與識別碼的實體時,皆會使用相同的實體執行個體。Before EF Core 3.0, the same entity instance would be used for every occurrence of an entity with a given type and ID. 如此符合追蹤查詢的行為。This matches the behavior of tracking queries. 例如,這個查詢:For example, this query:

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

會為每個與給定類別相關聯的 Product,傳回相同的 Category 執行個體。would return the same Category instance for each Product that is associated with the given category.

新的行為New behavior

從 EF Core 3.0 開始,當具有給定類型與識別碼的實體,出現在傳回圖形的不同位置時,將會建立不同的實體執行個體。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. 例如,即使當兩個產品與相同的類別相關聯,上述查詢現在會為每個 Category 傳回新的 Product 執行個體。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.

因此Why

身分識別解析 (也就是,決定實體與之前所發生的實體具有相同的類型與識別碼) 會加入額外的效能與記憶體負荷。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. 這通常會執行為何一開始就使用無追蹤查詢的計數器。This usually runs counter to why no-tracking queries are used in the first place. 此外,雖然身分識別解析有時非常有用,但若實體要序列化並會傳送給用戶端 (對無追蹤查詢而言很常見),則不需要。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.

風險降低Mitigations

若需要身分識別解析,請使用追蹤查詢。Use a tracking query if identity resolution is required.

查詢執行會在偵錯層級記錄已還原Query execution is logged at Debug level Reverted

追蹤問題 #14523Tracking Issue #14523

我們還原此變更的原因是 EF Core 3.0 中的新設定允許應用程式指定任何事件的記錄層級。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. 例如,若要將 SQL 的記錄切換到 Debug,請明確地在 OnConfiguringAddDbContext 中設定層級: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)));

實體執行個體上不會再設定暫存索引鍵值Temporary key values are no longer set onto entity instances

追蹤問題 #12378Tracking Issue #12378

舊的行為Old behavior

在 EF Core 3.0 以前,會對所有索引鍵屬性指派暫存值,這些屬性稍後會有資料庫產生的實值。Before EF Core 3.0, temporary values were assigned to all key properties that would later have a real value generated by the database. 這些暫存值通常是龐大的負值。Usually these temporary values were large negative numbers.

新的行為New behavior

從 3.0 開始,EF Core 會將暫存索引鍵值儲存為實體追蹤資訊的一部分,至於索引鍵屬性本身則保持不變。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.

因此Why

這項變更的目的是為了防止在將某個 DbContext 執行個體先前追蹤的實體移至不同的 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.

風險降低Mitigations

若應用程式會將主索引鍵指派給外部索引鍵以形成實體間關聯,則可能會在主索引鍵是由存放區產生並屬於 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. 這可透過下列方式來避免:This can be avoided by:

  • 不使用存放區產生的索引鍵。Not using store-generated keys.
  • 設定導覽屬性以形成關聯性,而不是設定外部索引鍵值。Setting navigation properties to form relationships instead of setting foreign key values.
  • 從實體的追蹤資訊取得實際暫存索引鍵值。Obtain the actual temporary key values from the entity's tracking information. 例如,context.Entry(blog).Property(e => e.Id).CurrentValue 會傳回暫存值,即使尚未設定 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 接受存放區產生的索引鍵值DetectChanges honors store-generated key values

追蹤問題 #14616Tracking Issue #14616

舊的行為Old behavior

在 EF Core 3.0 以前,DetectChanges 所發現未被追蹤的實體會以 Added 狀態追蹤,並在呼叫 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.

新的行為New behavior

從 EF Core 3.0 開始,如果實體使用產生的索引鍵值並已設定一些索引鍵值,則實體會以 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. 這表示實體的資料列假設存在,而且會在呼叫 SaveChanges 時更新。This means that a row for the entity is assumed to exist and it will be updated when SaveChanges is called. 如果未設定索引鍵值,或者如果實體類型未使用產生的索引鍵,則新的實體仍會如同舊版以 Added 追蹤。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.

因此Why

這項變更的目的是為了更輕鬆一致地使用中斷連接的實體圖形,同時使用存放區產生的索引鍵。This change was made to make it easier and more consistent to work with disconnected entity graphs while using store-generated keys.

風險降低Mitigations

如果實體類型已設定為使用產生的索引鍵,但針對新的執行個體明確設定了索引鍵值,這項變更可能會中斷應用程式。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. 修正方法是明確設定索引鍵屬性不使用產生的值。The fix is to explicitly configure the key properties to not use generated values. 例如,使用 Fluent API:For example, with the fluent API:

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

或者,使用資料註解:Or with data annotations:

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

現在預設會立即發生串聯刪除Cascade deletions now happen immediately by default

追蹤問題 #10114Tracking Issue #10114

舊的行為Old behavior

在 3.0 以前,除非呼叫 SaveChanges,否則 EF Core 不會套用串聯動作 (刪除必要主體或提供必要主體關聯性時刪除相依實體)。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.

新的行為New behavior

從 3.0 開始,EF Core 會在偵測到觸發條件時立即套用串聯動作。Starting with 3.0, EF Core applies cascading actions as soon as the triggering condition is detected. 例如,呼叫 context.Remove() 刪除主要實體會導致所有追蹤的相關必要相依項目也會立即設定為 DeletedFor example, calling context.Remove() to delete a principal entity will result in all tracked related required dependents also being set to Deleted immediately.

因此Why

這項變更是為了改善資料系結和審核案例的體驗,在此您必須瞭解將在呼叫_之前_刪除哪些實體 SaveChangesThis 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.

風險降低Mitigations

透過設定 context.ChangeTracker 可以還原舊行為。The previous behavior can be restored through settings on context.ChangeTracker. 例如:For example:

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

追蹤問題 #18022Tracking issue #18022

舊的行為Old behavior

在3.0 之前,立即透過運算子載入集合導覽 Include ,會導致關係資料庫產生多個查詢,每個相關實體類型各一個。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.

新的行為New behavior

從3.0 開始,EF Core 會在關係資料庫上產生具有聯結的單一查詢。Starting with 3.0, EF Core generates a single query with JOINs on relational databases.

因此Why

發出多個查詢來執行單一 LINQ 查詢,會造成許多問題,包括負面效能,因為需要多個資料庫往返,而當每個查詢可能觀察到資料庫的不同狀態時,就會發生資料一致性問題。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.

風險降低Mitigations

雖然技術上來說這不是一項重大變更,但當單一查詢在集合導覽上包含大量運算子時,可能會對應用程式效能造成相當大的影響 IncludeWhile 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. 如需詳細資訊和以更有效率的方式重寫查詢,請參閱此批註See this comment for more information and for rewriting queries in a more efficient way.

**

DeleteBehavior.Restrict 具有更簡潔的語意DeleteBehavior.Restrict has cleaner semantics

追蹤問題 #12661Tracking Issue #12661

舊的行為Old behavior

在 3.0 以前,DeleteBehavior.Restrict 使用 Restrict 語意在資料庫中建立外部索引鍵,但也以不明顯的方式變更內部修復。Before 3.0, DeleteBehavior.Restrict created foreign keys in the database with Restrict semantics, but also changed internal fixup in a non-obvious way.

新的行為New behavior

從 3.0 開始,DeleteBehavior.Restrict 會確保外部索引鍵使用 Restrict 語意來建立 (也就是不會有重疊顯示,拋出條件約束違規),不會影響 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.

因此Why

這項變更可藉由直覺方式提升使用 DeleteBehavior 的體驗,而不會發生非預期的副作用。This change was made to improve the experience for using DeleteBehavior in an intuitive manner, without unexpected side-effects.

風險降低Mitigations

使用 DeleteBehavior.ClientNoAction 可以還原舊行為。The previous behavior can be restored by using DeleteBehavior.ClientNoAction.

查詢類型會與實體類型合併Query types are consolidated with entity types

追蹤問題 #14194Tracking Issue #14194

舊的行為Old behavior

在 EF Core 3.0 以前,查詢類型可讓您查詢未以結構化方式定義主索引鍵的資料。Before EF Core 3.0, query types were a means to query data that doesn't define a primary key in a structured way. 換句話說,查詢類型是用於對應沒有索引鍵的實體類型 (較有可能來自檢視,但也有可能來自資料表),而一般實體類型是用於索引鍵可供使用時 (較有可能來自資料表,但也有可能來自檢視)。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).

新的行為New behavior

查詢類型現在會成為沒有主索引鍵的實體類型。A query type now becomes just an entity type without a primary key. 無索引鍵的實體類型功能與舊版查詢類型相同。Keyless entity types have the same functionality as query types in previous versions.

因此Why

這項變更的目的是為了降低查詢類型用途的混淆。This change was made to reduce the confusion around the purpose of query types. 具體來說,它們是無索引鍵的實體類型,因此本質上是唯讀的,但不應該只因為實體類型必須是唯讀就使用。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. 同樣地,它們通常會對應至檢視,但這只是因為檢視通常未定義索引鍵。Likewise, they are often mapped to views, but this is only because views often don't define keys.

風險降低Mitigations

API 的下列組件現已淘汰:The following parts of the API are now obsolete:

  • ModelBuilder.Query<>()-相反地,您 ModelBuilder.Entity<>().HasNoKey() 必須呼叫,將實體類型標記為沒有索引鍵。ModelBuilder.Query<>() - Instead ModelBuilder.Entity<>().HasNoKey() needs to be called to mark an entity type as having no keys. 為了避免在必須有主索引鍵但不符合慣例時設定錯誤,目前仍未將此設定為慣例。This would still not be configured by convention to avoid misconfiguration when a primary key is expected, but doesn't match the convention.
  • DbQuery<>-改 DbSet<> 為使用。DbQuery<> - Instead DbSet<> should be used.
  • DbContext.Query<>()-改 DbContext.Set<>() 為使用。DbContext.Query<>() - Instead DbContext.Set<>() should be used.

自有類型關聯性的設定 API 已變更Configuration API for owned type relationships has changed

追蹤問題 #12444 追蹤問題 #9148 追蹤問題 #14153Tracking Issue #12444 Tracking Issue #9148 Tracking Issue #14153

舊的行為Old behavior

在 EF Core 3.0 以前,會在呼叫 OwnsOneOwnsMany 之後直接執行自有關聯性的設定。Before EF Core 3.0, configuration of the owned relationship was performed directly after the OwnsOne or OwnsMany call.

新的行為New behavior

從 EF Core 3.0 開始,現在會有 Fluent API 使用 WithOwner() 將導覽屬性設定為擁有者。Starting with EF Core 3.0, there is now fluent API to configure a navigation property to the owner using WithOwner(). 例如:For example:

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

擁有者與自有之間關聯性的相關設定現在應該在 WithOwner() 之後鏈結,類似於其他關聯性的設定方式。The configuration related to the relationship between owner and owned should now be chained after WithOwner() similarly to how other relationships are configured. 但自有類型本身的設定仍會在 OwnsOne()/OwnsMany() 之後鏈結。While the configuration for the owned type itself would still be chained after OwnsOne()/OwnsMany(). 例如: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
            });
    });

此外,使用自有類型目標呼叫 Entity()HasOne()Set() 現在會擲回例外狀況。Additionally calling Entity(), HasOne(), or Set() with an owned type target will now throw an exception.

因此Why

這項變更的目的是為了更清楚地劃分設定自有類型本身,以及設定自有類型的「關聯性」__。This change was made to create a cleaner separation between configuring the owned type itself and the relationship to the owned type. 如此可避免 HasForeignKey 等方法的模稜兩可和混淆。This in turn removes ambiguity and confusion around methods like HasForeignKey.

風險降低Mitigations

將自有類型關聯性的設定變更為使用新的 API 介面,如上述範例所示。Change configuration of owned type relationships to use the new API surface as shown in the example above.

現在可選用以主體來共用資料表的相依實體Dependent entities sharing the table with the principal are now optional

追蹤問題 #9005Tracking Issue #9005

舊的行為Old behavior

請考慮下列模型: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; }
}

在 EF Core 3.0 之前,如果 OrderDetailsOrder 擁有,或明確對應至相同的資料表,則在新增新的 Order 時一律需要 OrderDetails 執行個體。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.

新的行為New behavior

從 3.0 開始,EF 允許新增 Order 而不需要 OrderDetails,並會對應所有 OrderDetails 屬性,除了可為 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. 查詢時,如果任何必要的屬性不具有值,或如果其具有主索引鍵以外的不必要屬性,且所有屬性都是 null,則 EF Core 會將 OrderDetails 設為 nullWhen 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.

風險降低Mitigations

如果您的模型具有與所有選擇性資料行共用相依資料表,但指向該資料表的導覽不預期為 null,則應修改應用程式,以處理當導覽為 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. 如果這不可行,則應將必要屬性新增至實體類型,或至少應有一個屬性指派其非 null 的值。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.

共用具有並行語彙基元資料行的所有實體,都必須將其對應至屬性All entities sharing a table with a concurrency token column have to map it to a property

追蹤問題 #14154Tracking Issue #14154

舊的行為Old behavior

請考慮下列模型: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");
}

在 EF Core 3.0之前,如果 OrderDetailsOrder 擁有,或明確對應至相同資料表,那麼僅更新 OrderDetails 將不會更新用戶端上的 Version 值,且下一次更新將會失敗。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.

新的行為New behavior

從 3.0 開始,EF Core 會將新的 Version 值傳播至 Order (如果其擁有 OrderDetails)。Starting with 3.0, EF Core propagates the new Version value to Order if it owns OrderDetails. 否則,在模型驗證期間會擲回例外狀況。Otherwise an exception is thrown during model validation.

因此Why

這項變更的目的,是為了避免在僅更新對應至相同資料表的其中一個實體時,出現過時的並行語彙基元值。This change was made to avoid a stale concurrency token value when only one of the entities mapped to the same table is updated.

風險降低Mitigations

共用資料表的所有實體,都必須包含對應至並行語彙基元資料行的屬性。All entities sharing the table have to include a property that is mapped to the concurrency token column. 在陰影狀態中建立一個是可能的:It's possible the create one in shadow-state:

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

在沒有擁有者的情況下,無法使用追蹤查詢來查詢擁有的實體Owned entities cannot be queried without the owner using a tracking query

追蹤問題 #18876Tracking Issue #18876

舊的行為Old behavior

在 EF Core 3.0 之前,您可以將擁有的實體當做任何其他導覽來查詢。Before EF Core 3.0, the owned entities could be queried as any other navigation.

context.People.Select(p => p.Address);

新的行為New behavior

從3.0 開始,如果追蹤查詢在沒有擁有者的情況下投射擁有的實體,EF Core 將會擲回。Starting with 3.0, EF Core will throw if a tracking query projects an owned entity without the owner.

因此Why

擁有的實體無法在沒有擁有者的情況下操作,因此在大部分的情況下,以這種方式查詢它們是一項錯誤。Owned entities cannot be manipulated without the owner, so in the vast majority of cases querying them in this way is an error.

風險降低Mitigations

如果必須追蹤所擁有的實體,以便在稍後進行修改,則擁有者應該包含在查詢中。If the owned entity should be tracked to be modified in any way later then the owner should be included in the query.

否則,請新增 AsNoTracking() 呼叫:Otherwise add an AsNoTracking() call:

context.People.Select(p => p.Address).AsNoTracking();

未對應類型的繼承屬性,現在會對應至所有衍生類型的單一資料行Inherited properties from unmapped types are now mapped to a single column for all derived types

追蹤問題 #13998Tracking Issue #13998

舊的行為Old behavior

請考慮下列模型: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>();
}

在 EF Core 3.0 之前,ShippingAddress 屬性會根據預設,為 BulkOrderOrder 對應至個別資料行。Before EF Core 3.0, the ShippingAddress property would be mapped to separate columns for BulkOrder and Order by default.

新的行為New behavior

從 3.0 開始,EF Core 只會為 ShippingAddress 建立一個資料行。Starting with 3.0, EF Core only creates one column for ShippingAddress.

因此Why

舊行為是非預期的。The old behavoir was unexpected.

風險降低Mitigations

屬性仍可以在衍生類型上明確對應至個別資料行: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");
}

外部索引鍵屬性慣例不會再比對與主體屬性相同的名稱The foreign key property convention no longer matches same name as the principal property

追蹤問題 #13274Tracking Issue #13274

舊的行為Old behavior

請考慮下列模型: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; }
}

在 EF Core 3.0 以前,CustomerId 屬性依照慣例會用於外部索引鍵。Before EF Core 3.0, the CustomerId property would be used for the foreign key by convention. 不過,如果 Order 是自有類型,則這也會將 CustomerId 設為主索引鍵,而這通常不符合預期。However, if Order is an owned type, then this would also make CustomerId the primary key and this isn't usually the expectation.

新的行為New behavior

從 3.0 開始,如果屬性的名稱與主體屬性相同,依照慣例,EF Core 不會嘗試將屬性用於外部索引鍵。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. 但仍會比對與主體屬性名稱串連的主體類型名稱,以及與主體屬性名稱模式串連的導覽名稱。Principal type name concatenated with principal property name, and navigation name concatenated with principal property name patterns are still matched. 例如: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; }
}

因此Why

這項變更的目的是為了避免錯誤地在自有類型上定義主索引鍵屬性。This change was made to avoid erroneously defining a primary key property on the owned type.

風險降低Mitigations

如果屬性預定會作為外部索引鍵,並因此成為主索引鍵的一部分,請明確進行這類設定。If the property was intended to be the foreign key, and hence part of the primary key, then explicitly configure it as such.

如果在 TransactionScope 完成之前未再使用,則資料庫連線現在已關閉Database connection is now closed if not used anymore before the TransactionScope has been completed

追蹤問題 #14218Tracking Issue #14218

舊的行為Old behavior

在 EF Core 3.0 之前,如果內容在 TransactionScope 內開啟連線,則當目前 TransactionScope 處於作用中時,連線將保持開啟。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();
    }
}

新的行為New behavior

從 3.0 開始,EF Core 在使用完連線後會將其關閉。Starting with 3.0, EF Core closes the connection as soon as it's done using it.

因此Why

此變更允許在相同 TransactionScope 中使用多個內容。This change allows to use multiple contexts in the same TransactionScope. 新的行為也符合 EF6。The new behavior also matches EF6.

風險降低Mitigations

如果連線需要保持開啟,則明確呼叫 OpenConnection() 可確保 EF Core 不會過早將其關閉: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();
    }
}

每個屬性會使用獨立的記憶體內部整數索引鍵產生Each property uses independent in-memory integer key generation

追蹤問題 #6872Tracking Issue #6872

舊的行為Old behavior

在 EF Core 3.0 以前,會針對所有記憶體內部整數索引鍵屬性使用一個共用值產生器。Before EF Core 3.0, one shared value generator was used for all in-memory integer key properties.

新的行為New behavior

從 EF Core 3.0 開始,當使用記憶體內部資料庫時,每個整數索引鍵屬性都會取得自己的值產生器。Starting with EF Core 3.0, each integer key property gets its own value generator when using the in-memory database. 此外,如果已刪除資料庫,則會重設所有資料表的索引鍵產生。Also, if the database is deleted, then key generation is reset for all tables.

因此Why

這項變更的目的是為了讓記憶體內部索引鍵產生與實際資料庫索引鍵產生更加一致,並改善在使用記憶體內部資料庫時隔離個別測試的能力。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.

風險降低Mitigations

這可能會中斷需要設定特定記憶體內部索引鍵值的應用程式。This can break an application that is relying on specific in-memory key values to be set. 請考慮改為不依賴特定索引鍵值,或更新以符合新行為。Consider instead not relying on specific key values, or updating to match the new behavior.

預設會使用支援欄位Backing fields are used by default

追蹤問題 #12430Tracking Issue #12430

舊的行為Old behavior

在 3.0 以前,即使屬性的支援欄位已知,EF Core 預設仍會使用屬性 getter 和 setter 方法來讀取和寫入屬性值。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. 例外是查詢執行,其中如果支援欄位已知,則會直接設定。The exception to this was query execution, where the backing field would be set directly if known.

新的行為New behavior

從 EF Core 3.0 開始,如果屬性的支援欄位已知,則 EF Core 會一律使用支援欄位來讀取和寫入該屬性。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. 如果應用程式需要將額外的行為編碼到 getter 或 setter 方法中,這可能會導致應用程式中斷。This could cause an application break if the application is relying on additional behavior coded into the getter or setter methods.

因此Why

這項變更的目的是為了防止 EF Core 預設在執行涉及實體的資料庫作業時,錯誤地觸發商務邏輯。This change was made to prevent EF Core from erroneously triggering business logic by default when performing database operations involving the entities.

風險降低Mitigations

透過在 ModelBuilder 上設定屬性存取模式可以還原 3.0 以前的行為。The pre-3.0 behavior can be restored through configuration of the property access mode on ModelBuilder. 例如:For example:

modelBuilder.UsePropertyAccessMode(PropertyAccessMode.PreferFieldDuringConstruction);

找到多個相容的支援欄位時擲回Throw if multiple compatible backing fields are found

追蹤問題 #12523Tracking Issue #12523

舊的行為Old behavior

在 EF Core 3.0 以前,如果有多個欄位符合尋找屬性支援欄位的規則,則會根據特定優先順序來選擇一個欄位。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. 這可能會導致在模稜兩可的情況下使用錯誤的欄位。This could cause the wrong field to be used in ambiguous cases.

新的行為New behavior

從 EF Core 3.0 開始,如果有多個欄位符合相同的屬性,則會擲回例外狀況。Starting with EF Core 3.0, if multiple fields are matched to the same property, then an exception is thrown.

因此Why

這項變更的目的是為了避免在只能有一個正確欄位的情況下,自動使用某個欄位而非另一個欄位。This change was made to avoid silently using one field over another when only one can be correct.

風險降低Mitigations

若屬性的支援欄位模稜兩可,則必須明確指定要使用的欄位。Properties with ambiguous backing fields must have the field to use specified explicitly. 例如,使用 Fluent API:For example, using the fluent API:

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

僅限欄位的屬性名稱應與欄位名稱相符Field-only property names should match the field name

舊的行為Old behavior

在 EF Core 3.0 之前,屬性可以由字串值指定,而且如果在 .NET 類型上找不到具有該名稱的屬性,則 EF Core 會嘗試使用慣例規則將它與欄位進行比對。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");

新的行為New behavior

從 EF Core 3.0 開始,僅限欄位的屬性必須與欄位名稱完全相符。Starting with EF Core 3.0, a field-only property must match the field name exactly.

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

因此Why

此變更是為了避免對兩個名稱相似的屬性使用相同欄位,也使僅限欄位屬性之比對規則與對應至 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.

風險降低Mitigations

僅限欄位屬性必須命名為與其所對應欄位相同的名稱。Field-only properties must be named the same as the field they are mapped to. 在3.0 以後的 EF Core 版本中,我們計畫重新啟用明確設定與屬性名稱不同的功能變數名稱(請參閱問題#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 再也不會呼叫 AddLogging 與 AddMemoryCacheAddDbContext/AddDbContextPool no longer call AddLogging and AddMemoryCache

追蹤問題 #14756Tracking Issue #14756

舊的行為Old behavior

在 EF Core 3.0 之前,呼叫 AddDbContextAddDbContextPool 也會透過對AddLoggingADDMEMORYCACHE的呼叫,向 DI 註冊記錄和記憶體快取服務。Before EF Core 3.0, calling AddDbContext or AddDbContextPool would also register logging and memory caching services with DI through calls to AddLogging and AddMemoryCache.

新的行為New behavior

從 EF Core 3.0 開始,AddDbContextAddDbContextPool 再也不會向相依性插入 (DI) 註冊這些服務。Starting with EF Core 3.0, AddDbContext and AddDbContextPool will no longer register these services with Dependency Injection (DI).

因此Why

EF Core 3.0 不會要求這些服務必須存在於應用程式的 DI 容器中。EF Core 3.0 does not require that these services are in the application's DI container. 不過,若 ILoggerFactory 已在應用程式的 DI 容器中註冊,則它仍會被 EF Core 使用。However, if ILoggerFactory is registered in the application's DI container, then it will still be used by EF Core.

風險降低Mitigations

若您的應用程式需要這些服務,請使用 AddLoggingAddMemoryCache 明確地向 DI 容器註冊它們。If your application needs these services, then register them explicitly with the DI container using AddLogging or AddMemoryCache.

AddEntityFramework * 新增具有大小限制的 IMemoryCacheAddEntityFramework* adds IMemoryCache with a size limit

追蹤問題 #12905Tracking Issue #12905

舊的行為Old behavior

在 EF Core 3.0 之前,呼叫 AddEntityFramework* 方法也會在沒有大小限制的情況下,向 DI 註冊記憶體快取服務。Before EF Core 3.0, calling AddEntityFramework* methods would also register memory caching services with DI without a size limit.

新的行為New behavior

從 EF Core 3.0 開始, AddEntityFramework* 會向大小限制註冊 IMemoryCache 服務。Starting with EF Core 3.0, AddEntityFramework* will register an IMemoryCache service with a size limit. 如果之後新增的任何其他服務相依于 IMemoryCache,他們可以快速達到預設限制,導致例外狀況或效能降低。If any other services added afterwards depend on IMemoryCache they can quickly reach the default limit causing exceptions or degraded performance.

因此Why

如果查詢快取邏輯中有錯誤,或動態產生查詢,則使用沒有限制的 IMemoryCache 可能會導致無法控制記憶體使用量。Using IMemoryCache without a limit could result in uncontrolled memory usage if there is a bug in query caching logic or the queries are generated dynamically. 具有預設限制可減少潛在的 DoS 攻擊。Having a default limit mitigates a potential DoS attack.

風險降低Mitigations

在大多數情況下 AddEntityFramework* ,如果也呼叫或,則不需要呼叫 AddDbContext AddDbContextPoolIn most cases calling AddEntityFramework* is not necessary if AddDbContext or AddDbContextPool is called as well. 因此,最好的緩和措施是移除 AddEntityFramework* 呼叫。Therefore, the best mitigation is to remove the AddEntityFramework* call.

如果您的應用程式需要這些服務,請事先使用AddMemoryCache,以直接向 DI 容器註冊 IMemoryCache 的執行。If your application needs these services, then register a IMemoryCache implementation explicitly with the DI container beforehand using AddMemoryCache.

DbContext.Entry 現在會執行本機 DetectChangesDbContext.Entry now performs a local DetectChanges

追蹤問題 #13552Tracking Issue #13552

舊的行為Old behavior

在 EF Core 3.0 以前,呼叫 DbContext.Entry 會導致偵測所有追蹤實體的變更。Before EF Core 3.0, calling DbContext.Entry would cause changes to be detected for all tracked entities. 這可確保在 EntityEntry 中公開的狀態為最新狀態。This ensured that the state exposed in the EntityEntry was up-to-date.

新的行為New behavior

從 EF Core 3.0 開始,呼叫 DbContext.Entry 現在只會嘗試在指定實體及其相關的任何追蹤主要實體中偵測變更。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. 這表示呼叫此方法可能還無法偵測到其他位置的變更,因此可能會影響應用程式狀態。This means that changes elsewhere may not have been detected by calling this method, which could have implications on application state.

請注意,如果 ChangeTracker.AutoDetectChangesEnabled 設定為 false,甚至是此本機變更偵測都會停用。Note that if ChangeTracker.AutoDetectChangesEnabled is set to false then even this local change detection will be disabled.

其他導致變更偵測的方法 (例如 ChangeTracker.EntriesSaveChanges) 仍會對所有追蹤實體進行完整的 DetectChangesOther methods that cause change detection--for example ChangeTracker.Entries and SaveChanges--still cause a full DetectChanges of all tracked entities.

因此Why

這項變更的目的是為了改善使用 context.Entry 的預設效能。This change was made to improve the default performance of using context.Entry.

風險降低Mitigations

在呼叫 Entry 之前明確呼叫 ChangeTracker.DetectChanges() 可確保 3.0 以前的行為。Call ChangeTracker.DetectChanges() explicitly before calling Entry to ensure the pre-3.0 behavior.

字串和位元組陣列索引鍵預設不是由用戶端產生String and byte array keys are not client-generated by default

追蹤問題 #14617Tracking Issue #14617

舊的行為Old behavior

在 EF Core 3.0 以前,可以使用 stringbyte[] 索引鍵屬性,而不需要明確設定非 Null 值。Before EF Core 3.0, string and byte[] key properties could be used without explicitly setting a non-null value. 在此情況下,會在用戶端以 GUID 形式產生索引鍵值,再序列化為 byte[] 的位元組。In such a case, the key value would be generated on the client as a GUID, serialized to bytes for byte[].

新的行為New behavior

從 EF Core 3.0 開始,系統會擲回例外狀況,指出尚未設定任何索引鍵值。Starting with EF Core 3.0 an exception will be thrown indicating that no key value has been set.

因此Why

這項變更是因為用戶端產生的 string/byte[] 值通常不太有用,而且預設行為使它很難以一般方式來推論產生的索引鍵值。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.

風險降低Mitigations

藉由明確指定索引鍵屬性應該在未設定其他非 Null 值時使用產生的值,即可取得 3.0 以前的行為。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. 例如,使用 Fluent API:For example, with the fluent API:

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

或者,使用資料註解:Or with data annotations:

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

ILoggerFactory 現在是限定範圍的服務ILoggerFactory is now a scoped service

追蹤問題 #14698Tracking Issue #14698

舊的行為Old behavior

在 EF Core 3.0 以前,ILoggerFactory 會註冊為單一服務。Before EF Core 3.0, ILoggerFactory was registered as a singleton service.

新的行為New behavior

從 EF Core 3.0 開始,ILoggerFactory 現在會註冊為限定範圍。Starting with EF Core 3.0, ILoggerFactory is now registered as scoped.

因此Why

這項變更的目的是為了允許記錄器與 DbContext 執行個體產生關聯,這可啟用其他功能,並避免某些異常行為案例,例如內部服務提供者遽增。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.

風險降低Mitigations

這項變更不應影響應用程式程式碼,除非在 EF Core 內部服務提供者上使用自訂服務註冊該程式碼。This change should not impact application code unless it is registering and using custom services on the EF Core internal service provider. 這並不常見。This isn't common. 在這些情況下,大部分的項目仍會運作,但相依於 ILoggerFactory 的任何單一服務需要變更,才能以不同方式取得 ILoggerFactoryIn 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.

如果您遇到上述情況,請在 EF Core GitHub 問題追蹤器上提出問題,讓我們知道您使用 ILoggerFactory 的方式,以便進一步了解未來如何才不會再次中斷。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.

消極式載入 Proxy 停止假設導覽屬性已完全載入Lazy-loading proxies no longer assume navigation properties are fully loaded

追蹤問題 #12780Tracking Issue #12780

舊的行為Old behavior

在 EF Core 3.0 以前,一旦處置 DbContext 之後,就無從得知實體上取自該內容的指定導覽屬性是否已完全載入。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. Proxy 會改為假設如有非 Null 值,會載入參考導覽;如果不是空的,則會載入集合導覽。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. 在這些情況下,嘗試消極式載入不會執行任何作業。In these cases, attempting to lazy-load would be a no-op.

新的行為New behavior

從 EF Core 3.0 開始,Proxy 會追蹤是否載入導覽屬性。Starting with EF Core 3.0, proxies keep track of whether or not a navigation property is loaded. 這表示嘗試存取在處置內容之後載入的導覽屬性一律不會執行任何作業,即使已載入的導覽是空的或 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. 相反地,如果在處置內容之後嘗試存取未載入的導覽屬性,則會擲回例外狀況,即使導覽屬性不是空集合也一樣。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. 如果發生這種情況,則表示應用程式程式碼嘗試在無效的時間使用消極式載入,應用程式應該變更為不要這麼做。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.

因此Why

這項變更的目的是為了在已處置的 DbContext 執行個體上嘗試消極式載入時,使行為一致且正確。This change was made to make the behavior consistent and correct when attempting to lazy-load on a disposed DbContext instance.

風險降低Mitigations

將應用程式程式碼更新為不要嘗試對已處置的內容進行消極式載入,或將此設定為不執行任何作業,如例外狀況訊息中所述。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.

過度建立內部服務提供者現在預設是錯誤Excessive creation of internal service providers is now an error by default

追蹤問題 #10236Tracking Issue #10236

舊的行為Old behavior

在 EF Core 3.0 以前,當應用程式建立異常數目的內部服務提供者時,會記錄一則警告。Before EF Core 3.0, a warning would be logged for an application creating a pathological number of internal service providers.

新的行為New behavior

從 EF Core 3.0 開始,此警告現在會視為錯誤,並會擲回例外狀況。Starting with EF Core 3.0, this warning is now considered and error and an exception is thrown.

因此Why

這項變更的目的是為了透過更明確公開此異常案例,藉以開發更完善的應用程式程式碼。This change was made to drive better application code through exposing this pathological case more explicitly.

風險降低Mitigations

遇到此錯誤時的最適當動作是了解根本原因,並停止建立這麼多的內部服務提供者。The most appropriate cause of action on encountering this error is to understand the root cause and stop creating so many internal service providers. 不過,透過設定 DbContextOptionsBuilder 可以將錯誤轉換回警告。However, the error can be converted back to a warning (or ignored) via configuration on the DbContextOptionsBuilder. 例如:For example:

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

使用單一字串呼叫之 HasOne/HasMany 的新行為New behavior for HasOne/HasMany called with a single string

追蹤問題 #9171Tracking Issue #9171

舊的行為Old behavior

在 EF Core 3.0 之前,使用單一字串呼叫 HasOneHasMany 的程式碼會以令人困惑的方式解譯。Before EF Core 3.0, code calling HasOne or HasMany with a single string was interpreted in a confusing way. 例如:For example:

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

程式碼看起來像是它使用 Entrance 瀏覽屬性將 Samurai 與一些其他實體類型相關,這可能是私用屬性。The code looks like it is relating Samurai to some other entity type using the Entrance navigation property, which may be private.

在現實中,此程式碼會在不使用瀏覽屬性的情況下嘗試建立與一些實體 (稱為 Entrance) 的關係。In reality, this code attempts to create a relationship to some entity type called Entrance with no navigation property.

新的行為New behavior

從 EF Core 3.0 開始,上述程式碼現在會執行像以前一樣的動作。Starting with EF Core 3.0, the code above now does what it looked like it should have been doing before.

因此Why

舊行為令人非常困惑,特別是當讀取設定程式碼與尋找錯誤時。The old behavior was very confusing, especially when reading the configuration code and looking for errors.

風險降低Mitigations

這只會造成已明確針對類型名稱使用字串設定關係,而未明確指定瀏覽屬性的應用程式中斷。This will only break applications that are explicitly configuring relationships using strings for type names and without specifying the navigation property explicitly. 這不是常見情況。This is not common. 先前的行為可透過明確地傳遞瀏覽屬性名稱的 null 來取得。The previous behavior can be obtained through explicitly passing null for the navigation property name. 例如:For example:

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

數個非同步方法的傳回類型已從 Task 變更為 ValueTaskThe return type for several async methods has been changed from Task to ValueTask

追蹤問題 #15184Tracking Issue #15184

舊的行為Old behavior

下列非同步方法先前傳回了 Task<T>The following async methods previously returned a Task<T>:

  • DbContext.FindAsync()
  • DbSet.FindAsync()
  • DbContext.AddAsync()
  • DbSet.AddAsync()
  • ValueGenerator.NextValueAsync() (和衍生類別)ValueGenerator.NextValueAsync() (and deriving classes)

新的行為New behavior

上述方法現在會透過相同的 T 傳回 ValueTask<T>,如同以前一樣。The aforementioned methods now return a ValueTask<T> over the same T as before.

因此Why

這項變更可降低叫用這些方法時產生的堆積配置數目,可改善一般效能。This change reduces the number of heap allocations incurred when invoking these methods, improving general performance.

風險降低Mitigations

僅等待上述 API 的應用程式只需要重新編譯,而不需要變更來源。Applications simply awaiting the above APIs only need to be recompiled - no source changes are necessary. 更複雜的使用方式 (例如將傳回的 Task 傳遞給 Task.WhenAny()) 通常需要藉由呼叫 AsTask() 將傳回的 ValueTask<T> 轉換為 Task<T>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. 請注意,這會抵消這項變更所帶來的配置減少。Note that this negates the allocation reduction that this change brings.

Relational:TypeMapping 註解現僅為 TypeMappingThe Relational:TypeMapping annotation is now just TypeMapping

追蹤問題 #9913Tracking Issue #9913

舊的行為Old behavior

類型對應註解的註解名稱之前是 "Relational:TypeMapping"。The annotation name for type mapping annotations was "Relational:TypeMapping".

新的行為New behavior

類型對應註解的註解名稱現在是 "TypeMapping"。The annotation name for type mapping annotations is now "TypeMapping".

因此Why

類型對應現在不只用於關聯式資料庫提供者。Type mappings are now used for more than just relational database providers.

風險降低Mitigations

這只會中斷直接將類型對應當做註解存取的應用程式,但這並不常見。This will only break applications that access the type mapping directly as an annotation, which isn't common. 最適當的修正動作是使用 API 介面存取類型對應,而不是直接使用註解。The most appropriate action to fix is to use API surface to access type mappings rather than using the annotation directly.

衍生類型上的 ToTable 會擲回例外狀況ToTable on a derived type throws an exception

追蹤問題 #11811Tracking Issue #11811

舊的行為Old behavior

在 EF Core 3.0 以前,會忽略衍生類型上呼叫的 ToTable(),因為唯一的繼承對應策略是對此案例無效的 TPH。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.

新的行為New behavior

從 EF Core 3.0 開始,以及在更新版本中準備新增 TPT 和 TPC 支援時,在衍生類型上呼叫的 ToTable() 現在會擲回例外狀況,以避免未來發生非預期的對應變更。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.

因此Why

目前無法將衍生類型對應至不同的資料表。Currently it isn't valid to map a derived type to a different table. 這項變更可避免未來有效執行時的中斷情況。This change avoids breaking in the future when it becomes a valid thing to do.

風險降低Mitigations

避免嘗試將衍生類型對應至其他資料表。Remove any attempts to map derived types to other tables.

ForSqlServerHasIndex 已取代為 HasIndexForSqlServerHasIndex replaced with HasIndex

追蹤問題 #12366Tracking Issue #12366

舊的行為Old behavior

在 EF Core 3.0 以前,ForSqlServerHasIndex().ForSqlServerInclude() 可讓您設定搭配 INCLUDE 使用的資料行。Before EF Core 3.0, ForSqlServerHasIndex().ForSqlServerInclude() provided a way to configure columns used with INCLUDE.

新的行為New behavior

從 EF Core 3.0 開始,關聯式層級現在支援對索引使用 IncludeStarting with EF Core 3.0, using Include on an index is now supported at the relational level. 使用 HasIndex().ForSqlServerInclude()Use HasIndex().ForSqlServerInclude().

因此Why

這項變更的目的是為了能夠使用 Include 將所有資料庫提供者的索引 API 合併到一個位置。This change was made to consolidate the API for indexes with Include into one place for all database providers.

風險降低Mitigations

使用新的 API,如上所示。Use the new API, as shown above.

中繼資料 API 變更Metadata API changes

追蹤問題 #214Tracking Issue #214

新的行為New behavior

下列屬性已轉換為擴充方法:The following properties were converted to extension methods:

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

因此Why

這項變更可簡化上述介面的實作。This change simplifies the implementation of the aforementioned interfaces.

風險降低Mitigations

使用新的擴充方法。Use the new extension methods.

提供者特定的中繼資料 API 變更Provider-specific Metadata API changes

追蹤問題 #214Tracking Issue #214

新的行為New behavior

提供者特定的擴充方法會壓平合併:The provider-specific extension methods will be flattened out:

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

因此Why

此變更可簡化上述延伸方法的實作。This change simplifies the implementation of the aforementioned extension methods.

風險降低Mitigations

使用新的擴充方法。Use the new extension methods.

EF Core 不會再傳送 SQLite FK 強制的 pragmaEF Core no longer sends pragma for SQLite FK enforcement

追蹤問題 #12151Tracking Issue #12151

舊的行為Old behavior

在 EF Core 3.0 以前,當開啟 SQLite 連線時,EF Core 會傳送 PRAGMA foreign_keys = 1Before EF Core 3.0, EF Core would send PRAGMA foreign_keys = 1 when a connection to SQLite is opened.

新的行為New behavior

從 EF Core 3.0 開始,當開啟 SQLite 連線時,EF Core 不會再傳送 PRAGMA foreign_keys = 1Starting with EF Core 3.0, EF Core no longer sends PRAGMA foreign_keys = 1 when a connection to SQLite is opened.

因此Why

這項變更是因為 EF Core 預設會使用 SQLitePCLRaw.bundle_e_sqlite3,這也表示預設會開啟 FK 強制,而不需要在每次開啟連線時明確啟用。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.

風險降低Mitigations

根據預設,會在預設用於 EF Core 的 SQLitePCLRaw.bundle_e_sqlite3 中啟用外部索引鍵。Foreign keys are enabled by default in SQLitePCLRaw.bundle_e_sqlite3, which is used by default for EF Core. 在其他情況下,則可以藉由在您的連接字串中指定 Foreign Keys=True 來啟用外部索引鍵。For other cases, foreign keys can be enabled by specifying Foreign Keys=True in your connection string.

Microsoft.EntityFrameworkCore.Sqlite 現在相依於 SQLitePCLRaw.bundle_e_sqlite3Microsoft.EntityFrameworkCore.Sqlite now depends on SQLitePCLRaw.bundle_e_sqlite3

舊的行為Old behavior

在 EF Core 3.0 以前,EF Core 會使用 SQLitePCLRaw.bundle_greenBefore EF Core 3.0, EF Core used SQLitePCLRaw.bundle_green.

新的行為New behavior

從 EF Core 3.0 開始,EF Core 會使用 SQLitePCLRaw.bundle_e_sqlite3Starting with EF Core 3.0, EF Core uses SQLitePCLRaw.bundle_e_sqlite3.

因此Why

這項變更的目的是為了讓用於 iOS 的 SQLite 版本與其他平台一致。This change was made so that the version of SQLite used on iOS consistent with other platforms.

風險降低Mitigations

若要在 iOS 上使用原生 SQLite 版本,請設定 Microsoft.Data.Sqlite 使用不同的 SQLitePCLRaw 套件組合。To use the native SQLite version on iOS, configure Microsoft.Data.Sqlite to use a different SQLitePCLRaw bundle.

GUID 值現在於 SQLite 上的儲存形式為 TEXTGuid values are now stored as TEXT on SQLite

追蹤問題 #15078Tracking Issue #15078

舊的行為Old behavior

GUID 值先前在 SQLite 上的儲存形式為 BLOB 值。Guid values were previously stored as BLOB values on SQLite.

新的行為New behavior

GUID 值現在會儲存為 TEXT。Guid values are now stored as TEXT.

因此Why

GUID 的二進位格式未標準化。The binary format of Guids is not standardized. 以 TEXT 的形式儲存值會提高資料庫與其他技術的相容性。Storing the values as TEXT makes the database more compatible with other technologies.

風險降低Mitigations

您可以參考以下方式執行 SQL,來將現有的資料庫移轉至新的格式。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';

在 EF Core 中,您也可以在這些屬性上設定值轉換器來繼續使用原本的行為。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 依然可以同時從 BLOB 及 TEXT 資料行讀取 GUID 值;但因為參數和常數的預設格式已變更,所以您可能需要對多數涉及 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.

Char 值現在於 SQLite 上會儲存為文字Char values are now stored as TEXT on SQLite

追蹤問題 #15020Tracking Issue #15020

舊的行為Old behavior

Char 值原先在 SQLite 上儲存為整數值。Char values were previously sored as INTEGER values on SQLite. 舉例來說,char 值 A 原先會儲存為整數值 65。For example, a char value of A was stored as the integer value 65.

新的行為New behavior

Char 值現在會儲存為 TEXT。Char values are now stored as TEXT.

因此Why

將值儲存為 TEXT 不但更加自然,也使資料庫與其他技術的相容性更高。Storing the values as TEXT is more natural and makes the database more compatible with other technologies.

風險降低Mitigations

您可以參考以下方式執行 SQL,來將現有的資料庫移轉至新的格式。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';

在 EF Core 中,您也可以在這些屬性上設定值轉換器來繼續使用原本的行為。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 也保留了讀取 INTEGER 和 TEXT 欄位字元值的功能,所以部分案例可能不需要任何動作。Microsoft.Data.Sqlite also remains capable of reading character values from both INTEGER and TEXT columns, so certain scenarios may not require any action.

移轉識別碼現在會使用不因文化特性而異的行事曆產生Migration IDs are now generated using the invariant culture's calendar

追蹤問題 #12978Tracking Issue #12978

舊的行為Old behavior

移轉識別碼原先會使用目前文化特性 (Culture) 的行事曆產生。Migration IDs were inadvertently generated using the current culture's calendar.

新的行為New behavior

移轉識別碼現在一律會使用不因文化特性而異的行事曆 (西曆) 產生。Migration IDs are now always generated using the invariant culture's calendar (Gregorian).

因此Why

更新資料庫或解決合併衝突時,移轉的順序相當重要。The order of migrations is important when updating the database or resolving merge conflicts. 使用無差異的行事曆可避免順序問題,使小組成員系統行事曆不同的問題不會發生。Using the invariant calendar avoids ordering issues that can result from team members having different system calendars.

風險降低Mitigations

此變更會影響年份大於西曆行事曆的非西曆行事曆使用者 (例如泰國佛曆)。This change affects anyone using a non-Gregorian calendar where the year is greater than the Gregorian calendar (like the Thai Buddhist calendar). 現有的移轉識別碼必須更新,以使新的移轉會在現有的移轉之後排序。Existing migration IDs will need to be updated so that new migrations are ordered after existing migrations.

您可在移轉設計工具檔案的移轉屬性中找到移轉識別碼。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
 {

移轉歷程記錄資料表也必須更新。The Migrations history table also needs to be updated.

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

已移除 UseRowNumberForPagingUseRowNumberForPaging has been removed

追蹤問題 #16400Tracking Issue #16400

舊的行為Old behavior

在 EF Core 3.0 之前,UseRowNumberForPaging 可用來問與 SQL Server 2008 相容的分頁產生 SQL。Before EF Core 3.0, UseRowNumberForPaging could be used to generate SQL for paging that is compatible with SQL Server 2008.

新的行為New behavior

從 EF Core 3.0 開始,EF 將只會針對與新版 SQL Server 相容的分頁產生 SQL。Starting with EF Core 3.0, EF will only generate SQL for paging that is only compatible with later SQL Server versions.

因此Why

我們正在進行此變更,因為 SQL Server 2008 不再是支援的產品 (英文) 且更新此功能以搭配 EF Core 3.0 中的查詢變更使用是一個大工程。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.

風險降低Mitigations

我們建議更新為新版 SQL Server,或使用較高的相容性層級,以支援產生的 SQL。We recommend updating to a newer version of SQL Server, or using a higher compatibility level, so that the generated SQL is supported. 儘管如此,若您無法這樣做,請在追蹤問題下註解並提供詳細資料。That being said, if you are unable to do this, then please comment on the tracking issue with details. 我們可能會根據意見反應重新審視此決定。We may revisit this decision based on feedback.

已從 IDbContextOptionsExtension 移除延伸模組資訊/中繼資料Extension info/metadata has been removed from IDbContextOptionsExtension

追蹤問題 #16119Tracking Issue #16119

舊的行為Old behavior

用於提供有關延伸模組織中繼資料的 IDbContextOptionsExtension 包含方法。IDbContextOptionsExtension contained methods for providing metadata about the extension.

新的行為New behavior

這些方法已移動到新的 DbContextOptionsExtensionInfo 抽象基底類別,這是從新的 IDbContextOptionsExtension.Info 屬性傳回的。These methods have been moved onto a new DbContextOptionsExtensionInfo abstract base class, which is returned from a new IDbContextOptionsExtension.Info property.

因此Why

在從 2.0 升級到 3.0 的程序中,我們必須新增或變更這些方法數次。Over the releases from 2.0 to 3.0 we needed to add to or change these methods several times. 將它們分成新的抽象基底類別可讓我們更輕鬆地在不變更現有延伸模組的情況下進行此類變更。Breaking them out into a new abstract base class will make it easier to make these kind of changes without breaking existing extensions.

風險降低Mitigations

更新延伸模組以遵循新模式。Update extensions to follow the new pattern. 您可以在 EF Core 原始程式碼中各種不同延伸模組之 IDbContextOptionsExtension 的許多實作中找到範例。Examples are found in the many implementations of IDbContextOptionsExtension for different kinds of extensions in the EF Core source code.

已重新命名 LogQueryPossibleExceptionWithAggregateOperatorLogQueryPossibleExceptionWithAggregateOperator has been renamed

追蹤問題 #10985Tracking Issue #10985

變更Change

RelationalEventId.LogQueryPossibleExceptionWithAggregateOperator 已經重新命名為 RelationalEventId.LogQueryPossibleExceptionWithAggregateOperatorWarningRelationalEventId.LogQueryPossibleExceptionWithAggregateOperator has been renamed to RelationalEventId.LogQueryPossibleExceptionWithAggregateOperatorWarning.

因此Why

使這個警告事件的命名與其他所有警告事件一致。Aligns the naming of this warning event with all other warning events.

風險降低Mitigations

使用新的名稱。Use the new name. (注意,事件識別碼未變更。)(Note that the event ID number has not changed.)

讓 API 的外部索引鍵限制式名稱更清楚Clarify API for foreign key constraint names

追蹤問題 #10730Tracking Issue #10730

舊的行為Old behavior

在 EF Core 3.0 前,外部索引鍵限制式名稱僅為 "name"。Before EF Core 3.0, foreign key constraint names were referred to as simply the "name". 例如:For example:

var constraintName = myForeignKey.Name;

新的行為New behavior

從 EF Core 3.0 開始,外部索引鍵限制式名稱現為 "constraint name"。Starting with EF Core 3.0, foreign key constraint names are now referred to as the "constraint name". 例如:For example:

var constraintName = myForeignKey.ConstraintName;

因此Why

此變更可讓此領域中的命名一致,同時清楚指出這是外部索引鍵限制式的名稱,而非定義外部索引鍵的資料行或屬性名稱。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.

風險降低Mitigations

使用新的名稱。Use the new name.

IRelationalDatabaseCreator.HasTables/HasTablesAsync 已設定為公用IRelationalDatabaseCreator.HasTables/HasTablesAsync have been made public

追蹤問題 #15997Tracking Issue #15997

舊的行為Old behavior

在 EF Core 3.0 之前,這些方法已受保護。Before EF Core 3.0, these methods were protected.

新的行為New behavior

從 EF Core 3.0 開始,這些方法為公用。Starting with EF Core 3.0, these methods are public.

因此Why

這些方法是由 EF 用來判斷資料庫是否已建立但為空資料庫。These methods are used by EF to determine if a database is created but empty. 當判斷是否要套用移轉時,這在 EF 外部也很實用。This can also be useful from outside EF when determining whether or not to apply migrations.

風險降低Mitigations

變更任何覆寫的可存取性。Change the accessibility of any overrides.

Microsoft.EntityFrameworkCore.Design 現在是 DevelopmentDependency 套件Microsoft.EntityFrameworkCore.Design is now a DevelopmentDependency package

追蹤問題 #11506Tracking Issue #11506

舊的行為Old behavior

在 EF Core 3.0 之前,Microsoft.EntityFrameworkCore.Design 是標準 NuGet 套件,其組件可由相依於它的的專案參考。Before EF Core 3.0, Microsoft.EntityFrameworkCore.Design was a regular NuGet package whose assembly could be referenced by projects that depended on it.

新的行為New behavior

從 EF Core 3.0 開始,它是 DevelopmentDependency 套件。Starting with EF Core 3.0, it is a DevelopmentDependency package. 這表示相依性不會傳遞至其他專案,而且根據預設,您無法再參考其元件。This means that the dependency won't flow transitively into other projects, and that you can no longer, by default, reference its assembly.

因此Why

此套件旨在用於設計階段。This package is only intended to be used at design time. 部署的應用程式不應該參考它。Deployed applications shouldn't reference it. 將套件設定為 DevelopmentDependency 會加強此建議。Making the package a DevelopmentDependency reinforces this recommendation.

風險降低Mitigations

如果您需要參考此封裝來覆寫 EF Core 的設計階段行為,則可以更新專案中的 PackageReference 專案中繼資料。If you need to reference this package to override EF Core's design-time behavior, then you can update PackageReference item metadata in your project.

<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>

若以可轉移方式透過 Microsoft.EntityFrameworkCore.Tools 參考該套件,您將必須新增明確的 PackageReference 到該套件以變更其中繼資料。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. 這類明確參考必須加入至需要封裝之類型的任何專案中。Such an explicit reference must be added to any project where the types from the package are needed.

SQLitePCL.raw 已更新為 2.0.0 版SQLitePCL.raw updated to version 2.0.0

追蹤問題 #14824Tracking Issue #14824

舊的行為Old behavior

Microsoft.EntityFrameworkCore.Sqlite 先前相依於 SQLitePCL.raw 的 1.1.12 版。Microsoft.EntityFrameworkCore.Sqlite previously depended on version 1.1.12 of SQLitePCL.raw.

新的行為New behavior

我們已更新套件,以相依于版本2.0.0。We've updated our package to depend on version 2.0.0.

因此Why

2.0.0 版的 SQLitePCL.raw 以 .NET Standard 2.0 為目標。Version 2.0.0 of SQLitePCL.raw targets .NET Standard 2.0. 它先前以 .NET Standard 1.1 為目標,這需要大量的大量的可轉移套件才能運作。It previously targeted .NET Standard 1.1 which required a large closure of transitive packages to work.

風險降低Mitigations

SQLitePCL.raw version 2.0.0 包括一些中斷性變更。SQLitePCL.raw version 2.0.0 includes some breaking changes. 如需詳細資料,請參閱版本資訊。See the release notes for details.

NetTopologySuite 已更新為 2.0.0 版NetTopologySuite updated to version 2.0.0

追蹤問題 #14825Tracking Issue #14825

舊的行為Old behavior

空間套件先前相依於 NetTopologySuite 1.15.1 版。The spatial packages previously depended on version 1.15.1 of NetTopologySuite.

新的行為New behavior

我們已更新我們的套件以相依於 2.0.0 版。We've update our package to depend on version 2.0.0.

因此Why

NetTopologySuite 2.0.0 版旨在解決 EF Core 使用者遇到的數個可用性問題。Version 2.0.0 of NetTopologySuite aims to address several usability issues encountered by EF Core users.

風險降低Mitigations

NetTopologySuite 2.0.0 版包括一些中斷性變更。NetTopologySuite version 2.0.0 includes some breaking changes. 如需詳細資料,請參閱版本資訊。See the release notes for details.

SqlClient 是用來取代 SqlClient 的資料。Microsoft.Data.SqlClient is used instead of System.Data.SqlClient

追蹤問題 #15636Tracking Issue #15636

舊的行為Old behavior

Microsoft.entityframeworkcore 先前的相依于 SqlClient。Microsoft.EntityFrameworkCore.SqlServer previously depended on System.Data.SqlClient.

新的行為New behavior

我們已更新套件,以相依于 SqlClient。We've updated our package to depend on Microsoft.Data.SqlClient.

因此Why

SqlClient 是用於 SQL Server 的旗艦版資料存取驅動程式,而 SqlClient 不再是開發的重點。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. 某些重要功能(例如 Always Encrypted)僅適用于 SqlClient。Some important features, such as Always Encrypted, are only available on Microsoft.Data.SqlClient.

風險降低Mitigations

如果您的程式碼會直接相依于 SqlClient,您必須將它變更為參考 SqlClient。因為這兩個套件會維持非常高程度的 API 相容性,所以這應該只是簡單的封裝和命名空間變更。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.

必須設定多個不明確的自我參考關聯性Multiple ambiguous self-referencing relationships must be configured

追蹤問題 #13573Tracking Issue #13573

舊的行為Old behavior

具有多個自我參考單向導覽屬性和相符 FK 的實體類型,不當設定為單一關聯性。An entity type with multiple self-referencing uni-directional navigation properties and matching FKs was incorrectly configured as a single relationship. 例如: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; }
}

新的行為New behavior

這種情況現在會在模型建立過程中偵測到,而且會擲回例外狀況,指出模型不明確。This scenario is now detected in model building and an exception is thrown indicating that the model is ambiguous.

因此Why

產生的模型不明確,在這種情況下通常會有錯誤。The resultant model was ambiguous and will likely usually be wrong for this case.

風險降低Mitigations

使用關聯性的完整設定。Use full configuration of the relationship. 例如:For example:

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

DbFunction。架構為 null 或空字串,將其設定為模型的預設架構DbFunction.Schema being null or empty string configures it to be in model's default schema

追蹤問題 #12757Tracking Issue #12757

舊的行為Old behavior

以架構為空字串所設定的 DbFunction,在沒有架構的情況下被視為內建函數。A DbFunction configured with schema as an empty string was treated as built-in function without a schema. 例如,下列程式碼會將 DatePart CLR 函數對應至 DATEPART 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();

新的行為New behavior

所有的 DbFunction 對應都會被視為對應至使用者定義的函數。All DbFunction mappings are considered to be mapped to user defined functions. 因此,空的字串值會將函數放在模型的預設架構內。Hence empty string value would put the function inside the default schema for the model. 這可能是透過 Fluent API 明確設定的架構 modelBuilder.HasDefaultSchema()dbo 否則為。Which could be the schema configured explicitly via fluent API modelBuilder.HasDefaultSchema() or dbo otherwise.

因此Why

先前的架構是空的,這是將該函式內建的方法,但該邏輯僅適用于 SqlServer,其中內建函數不屬於任何架構。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.

風險降低Mitigations

手動設定 DbFunction 的轉譯,以將其對應至內建函數。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));