共用方式為


Entity Framework 6 提供者模型

Entity Framework 提供者模型可讓 Entity Framework 與不同類型的資料庫伺服器搭配使用。 例如,可以插入一個提供者,以允許 EF 用於 Microsoft SQL Server,而另一個提供者可以插入以允許 EF 用於 Microsoft SQL Server Compact Edition。 您可以在 Entity Framework 提供者頁面上找到 我們認識的 EF6 提供者。

EF 與提供者互動的方式需要某些變更,才能在開放原始碼授權下釋放 EF。 這些變更需要針對 EF6 元件重建 EF 提供者,以及註冊提供者的新機制。

重建

使用 EF6 時,先前是 .NET Framework 一部分的核心程式代碼現在會以頻外 (OOB) 元件的形式提供。 如需如何針對 EF6 建置應用程式的詳細資料,請參閱 EF6 更新應用程式頁面。 提供者也需要使用這些指示重建。

提供者類型概觀

EF 提供者實際上是 CLR 類型所定義的提供者特定服務集合,這些服務會從 (針對基類) 或實作 (針對介面) 延伸。 這兩項服務是 EF 運作的基礎和必要專案。 其他則是選擇性的,只有在需要特定功能且/或這些服務的預設實作不適用於目標的特定資料庫伺服器時,才需要實作。

基本提供者類型

DbProviderFactory

EF 取決於具有衍生自 System.Data.Common.DbProviderFactory 的類型,以執行所有低階資料庫存取。 DbProviderFactory 實際上不是 EF 的一部分,而是 .NET Framework 中的類別,提供可供 EF、其他 O/RM 或應用程式直接使用之 ADO.NET 提供者的進入點,以取得與提供者無關的連線、命令、參數和其他 ADO.NET 抽象概念的實例。 如需 DbProviderFactory 的詳細資訊,請參閱 MSDN 檔中的 ADO.NET

DbProviderServices

EF 相依于具有衍生自 DbProviderServices 的類型,以在已由 ADO.NET 提供者提供的功能之上,提供 EF 所需的額外功能。 在舊版 EF 中,DbProviderServices 類別是 .NET Framework 的一部分,而且位於 System.Data.Common 命名空間中。 從 EF6 開始,這個類別現在是 EntityFramework.dll 的一部分,且位於 System.Data.Entity.Core.Common 命名空間中。

如需 DbProviderServices 實作基本功能的詳細資訊,請參閱 MSDN 。 不過,請注意,在撰寫此資訊時,EF6 不會更新這項資訊,不過大部分的概念仍然有效。 DbProviderServices 的 SQL Server 和 SQL Server Compact 實作也會簽入至 開放原始碼程式碼基底 ,並可作為其他實作的實用參考。

在舊版 EF 中,會直接從 ADO.NET 提供者取得要使用的 DbProviderServices 實作。 這是藉由將 DbProviderFactory 轉換成 IServiceProvider 並呼叫 GetService 方法來完成。 這緊密結合 EF 提供者到 DbProviderFactory。 這個結合會阻止 EF 移出 .NET Framework,因此針對 EF6,已移除這個緊密結合,而且現在直接在應用程式的組態檔或以程式碼為基礎的組態中註冊 DbProviderServices 的實作,如 下方的註冊 DbProviderServices 一節所述。

其他服務

除了上述基本服務之外,EF 也會使用許多其他服務,這些服務一律或有時是提供者特定的。 這些服務的預設提供者特定實作可由 DbProviderServices 實作提供。 當 DbProviderServices 類型未提供預設值時,應用程式也可以覆寫這些服務的實作,或提供實作。 以下解析 其他服務 一節會更詳細地說明這一點。

提供者可能感興趣的其他服務類型如下所列。 如需這些服務類型的詳細資訊,請參閱 API 檔。

IDbExecutionStrategy

這是選擇性服務,可讓提供者在對資料庫執行查詢和命令時實作重試或其他行為。 如果未提供任何實作,則 EF 只會執行命令並傳播擲回的任何例外狀況。 對於 SQL Server,此服務用來提供重試原則,在針對 SQL Azure 等雲端式資料庫伺服器執行時特別有用。

IDb連線ionFactory

這是選擇性的服務,允許提供者在只指定資料庫名稱時,依慣例建立 Db連線ion 物件。 請注意,雖然此服務可由 DbProviderServices 實作解析,但自 EF 4.1 起就已經存在,也可以在組態檔或程式碼中明確設定。 如果提供者註冊為預設提供者,且未在其他地方設定預設連線處理站,則提供者只會有機會解析此服務(請參閱 下面的預設提供者 )。

DbSpatialServices

這是選擇性服務,可讓提供者新增對地理和幾何空間類型的支援。 必須提供此服務的實作,應用程式才能搭配空間類型使用 EF。 DbSptialServices 有兩種方式要求。 首先,會使用 DbProviderInfo 物件(其中包含不因名稱與資訊清單權杖)作為金鑰,要求提供者特定的空間服務。 其次,可以要求 DbSpatialServices 沒有金鑰。 這可用來解析建立獨立 DbGeography 或 DbGeometry 類型時所使用的「全域空間提供者」。

MigrationSqlGenerator

這是選擇性服務,可讓 EF 移轉用於建立和修改 Code First 的資料庫架構時所使用的 SQL 產生。 需要實作才能支援移轉。 如果提供實作,則在使用資料庫初始化運算式或 Database.Create 方法建立資料庫時,也會使用它。

Func < Db連線ion, 字串, HistoryCoNtextFactory>

這是選擇性的服務,可讓提供者設定 HistoryCoNtext 與 __MigrationHistory EF 移轉所使用的資料表的對應。 HistoryCoNtext 是 Code First DbCoNtext,可以使用一般 Fluent API 來設定變更資料表名稱和資料行對應規格等專案。 如果該提供者支援所有預設資料表和資料行對應,EF 針對所有提供者所傳回之此服務的預設實作,就可能適用于指定的資料庫伺服器。 在這種情況下,提供者不需要提供此服務的實作。

IDbProviderFactoryResolver

這是選擇性的服務,可從指定的 Db連線ion 物件取得正確的 DbProviderFactory。 EF 針對所有提供者傳回之此服務的預設實作是適用于所有提供者。 不過,在 .NET 4 上執行時,如果 Db連線ion,則無法從其中一個公開存取 DbProviderFactory。 因此,EF 會使用一些啟發學習法來搜尋已註冊的提供者來尋找相符專案。 對於某些提供者,這些啟發學習法可能會失敗,在這種情況下,提供者應該提供新的實作。

註冊 DbProviderServices

要使用的 DbProviderServices 實作可以在應用程式的組態檔 (app.config 或 web.config) 或使用程式碼型組態中註冊。 在任一情況下,註冊都會使用提供者的「不變名稱」作為金鑰。 這可讓多個提供者在單一應用程式中註冊及使用。 用於 EF 註冊的不變異名稱與用於 ADO.NET 提供者註冊和連接字串的不因名稱相同。 例如,針對 SQL Server,會使用非變異名稱 「System.Data.SqlClient」。

組態檔註冊

要使用的 DbProviderServices 類型會在應用程式組態檔之 entityFramework 區段的提供者清單中註冊為提供者專案。 例如:

<entityFramework>
  <providers>
    <provider invariantName="My.Invariant.Name" type="MyProvider.MyProviderServices, MyAssembly" />
  </providers>
</entityFramework>

別字符串必須是要使用的 DbProviderServices 實作元件限定型別名稱。

程式碼架構註冊

從 EF6 提供者開始,也可以使用程式碼註冊。 這可讓 EF 提供者使用,而不需要變更應用程式的組態檔。 若要使用程式碼型組態,應用程式應該建立 DbConfiguration 類別,如程式碼型組態檔 中所述 。 DbConfiguration 類別的建構函式應該接著呼叫 SetProviderServices 來註冊 EF 提供者。 例如:

public class MyConfiguration : DbConfiguration
{
    public MyConfiguration()
    {
        SetProviderServices("My.New.Provider", new MyProviderServices());
    }
}

解決其他服務

如上述 提供者類型概觀 一節所述,DbProviderServices 類別也可用來解析其他服務。 這是可能的,因為 DbProviderServices 會實作 IDbDependencyResolver,而且每個已註冊的 DbProviderServices 類型都會新增為「預設解析程式」。 相依性解析 會更詳細地說明 IDbDpendencyResolver 機制。 不過,不需要瞭解此規格中的所有概念,以解析提供者中的其他服務。

提供者解析其他服務最常見的方式是針對 DbProviderServices 類別建構函式中的每個服務呼叫 DbProviderServices.AddDependencyResolver。 例如,SqlProviderServices (SQL Server 的 EF 提供者) 有類似這個的程式碼進行初始化:

private SqlProviderServices()
{
    AddDependencyResolver(new SingletonDependencyResolver<IDbConnectionFactory>(
        new SqlConnectionFactory()));

    AddDependencyResolver(new ExecutionStrategyResolver<DefaultSqlExecutionStrategy>(
        "System.data.SqlClient", null, () => new DefaultSqlExecutionStrategy()));

    AddDependencyResolver(new SingletonDependencyResolver<Func<MigrationSqlGenerator>>(
        () => new SqlServerMigrationSqlGenerator(), "System.data.SqlClient"));

    AddDependencyResolver(new SingletonDependencyResolver<DbSpatialServices>(
        SqlSpatialServices.Instance,
        k =>
        {
            var asSpatialKey = k as DbProviderInfo;
            return asSpatialKey == null
                || asSpatialKey.ProviderInvariantName == ProviderInvariantName;
        }));
}

此建構函式會使用下列協助程式類別:

  • SingletonDependencyResolver:提供簡單的方法來解析 Singleton 服務,也就是每次呼叫 GetService 時,都會傳回相同實例的服務。 暫時性服務通常會註冊為單一處理站,用來視需要建立暫時性實例。
  • ExecutionStrategyResolver:傳回 IExecutionStrategy 實作的特定解析程式。

除了使用 DbProviderServices.AddDependencyResolver,您也可以覆寫 DbProviderServices.GetService 並直接解析其他服務。 當 EF 需要特定類型所定義的服務,而且在某些情況下,針對指定的索引鍵,將會呼叫這個方法。 如果可以,方法應該傳回服務,或傳回 null 以選擇不傳回服務,而是允許另一個類別加以解析。 例如,若要解析預設連線處理站,GetService 中的程式碼看起來可能如下所示:

public override object GetService(Type type, object key)
{
    if (type == typeof(IDbConnectionFactory))
    {
        return new SqlConnectionFactory();
    }
    return null;
}

註冊順序

當多個 DbProviderServices 實作在應用程式的組態檔中註冊時,它們會依照列出的順序新增為次要解析程式。 由於解析程式一律會新增至次要解析程式鏈結的頂端,這表示清單結尾的提供者將有機會在其他人之前解析相依性。 (這一開始似乎有點反直覺,但如果您想像將每個提供者從清單中取出並堆疊在現有提供者之上,這是合理的。

此順序通常無關緊要,因為大部分的提供者服務都是提供者特定的,且由提供者不因名稱而異。 不過,對於提供者不因名稱不變或其他提供者特定金鑰所編制的服務,服務將會根據此順序來解析。 例如,如果未明確設定其他位置的不同,則預設連接處理站會來自鏈結中最上層的提供者。

其他組態檔註冊

您可以在應用程式的組態檔中明確註冊上述的一些其他提供者服務。 完成此動作時,將會使用組態檔中的註冊,而不是 DbProviderServices 實作的 GetService 方法所傳回的任何專案。

註冊預設連線處理站

從 EF5 開始,EntityFramework NuGet 套件會自動在組態檔中註冊 SQL Express 連線處理站或 LocalDb 連線處理站。

例如:

<entityFramework>
  <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" >
</entityFramework>

類型 是預設連接處理站的元件限定類型名稱,必須實作 IDb連線ionFactory。

建議提供者 NuGet 套件在安裝時以這種方式設定預設連線處理站。 請參閱 下方提供者 的 NuGet 套件。

其他 EF6 提供者變更

空間提供者變更

支援空間類型的提供者現在必須在衍生自 DbSpatialDataReader 的類別上實作一些額外的方法:

  • public abstract bool IsGeographyColumn(int ordinal)
  • public abstract bool IsGeometryColumn(int ordinal)

也有新的非同步版本現有的方法,建議覆寫為預設實作委派給同步方法,因此不會以非同步方式執行:

  • public virtual Task<DbGeography> GetGeographyAsync(int ordinal, CancellationToken cancellationToken)
  • public virtual Task<DbGeometry> GetGeometryAsync(int ordinal, CancellationToken cancellationToken)

Enumerable.Contains 的原生支援

EF6 引進了新的運算式類型 DbInExpression,其已新增,以解決 LINQ 查詢中使用 Enumerable.Contains 的效能問題。 DbProviderManifest 類別有新的虛擬方法 SupportsInExpression,由 EF 呼叫,以判斷提供者是否處理新的運算式類型。 為了與現有的提供者實作相容,方法會傳回 false。 為了受益于這項改進,EF6 提供者可以新增程式碼來處理 DbInExpression 並覆寫 SupportsInExpression 以傳回 true。 您可以呼叫 DbExpressionBuilder.In 方法來建立 DbInExpression 的實例。 DbInExpression 實例是由 DbExpression 所組成,通常代表資料表資料行,以及要測試相符專案的 DbConstantExpression 清單。

提供者的 NuGet 套件

讓 EF6 提供者可供使用的方法之一,就是將它發行為 NuGet 套件。 使用 NuGet 套件具有下列優點:

  • 使用 NuGet 輕鬆地將提供者註冊新增至應用程式的組態檔
  • 您可以對組態檔進行其他變更,以設定預設連接處理站,讓慣例所建立的連線會使用已註冊的提供者
  • NuGet 會處理新增系結重新導向,讓 EF6 提供者即使在發行新的 EF 套件之後仍應繼續運作

其中一個範例是包含在 開放原始碼程式碼基底 中的 EntityFramework.SqlServerCompact 套件 。 此套件提供建立 EF 提供者 NuGet 套件的良好範本。

PowerShell 命令

安裝 EntityFramework NuGet 套件時,它會註冊 PowerShell 模組,其中包含兩個對提供者套件非常有用的命令:

  • Add-EFProvider 會在目標專案的組態檔中新增提供者的新實體,並確定它位於已註冊提供者清單的結尾。
  • Add-EFDefault連線ionFactory 會在目標專案的組態檔中新增或更新預設值連線ionFactory 註冊。

這兩個命令都會負責將 entityFramework 區段新增至組態檔,並視需要新增提供者集合。

預期會從 install.ps1 NuGet 腳本呼叫這些命令。 例如,SQL Compact 提供者的 install.ps1 看起來如下所示:

param($installPath, $toolsPath, $package, $project)
Add-EFDefaultConnectionFactory $project 'System.Data.Entity.Infrastructure.SqlCeConnectionFactory, EntityFramework' -ConstructorArguments 'System.Data.SqlServerCe.4.0'
Add-EFProvider $project 'System.Data.SqlServerCe.4.0' 'System.Data.Entity.SqlServerCompact.SqlCeProviderServices, EntityFramework.SqlServerCompact'</pre>

您可以在 封裝管理員 [主控台] 視窗中使用 get-help 取得這些命令的詳細資訊。

包裝提供者

包裝提供者是 EF 和/或 ADO.NET 提供者,會包裝現有的提供者,以流量分析或追蹤功能等其他功能來擴充它。 包裝提供者可以正常註冊,但藉由攔截提供者相關服務的解析,在執行時間設定包裝提供者通常更方便。 DbConfiguration 類別上的靜態事件 OnLockingConfiguration 可用來執行此動作。

在 EF 判斷要從何處取得應用程式網域的所有 EF 組態,但在鎖定以供使用之前,就會呼叫 OnLockingConfiguration。 在應用程式啟動時(使用 EF 之前),應用程式應該註冊此事件的事件處理常式。 (我們正在考慮在組態檔中新增註冊此處理程式的支援,但這尚未受到支援。然後,事件處理常式應該針對需要包裝的每個服務呼叫 ReplaceService。

例如,若要包裝 IDb連線ionFactory 和 DbProviderService,應該註冊類似如下的處理常式:

DbConfiguration.OnLockingConfiguration +=
    (_, a) =>
    {
        a.ReplaceService<DbProviderServices>(
            (s, k) => new MyWrappedProviderServices(s));

        a.ReplaceService<IDbConnectionFactory>(
            (s, k) => new MyWrappedConnectionFactory(s));
    };

已解析的服務,現在應該與用來解析服務的索引鍵一起包裝至處理常式。 處理常式接著可以包裝此服務,並以包裝的版本取代傳回的服務。

使用 EF 解析 DbProviderFactory

DbProviderFactory 是 EF 所需的其中一種基本提供者類型,如上述提供者類型概觀 一節所述 。 如先前所述,這不是 EF 類型,註冊通常不是 EF 組態的一部分,而是 machine.config 檔案和/或應用程式組態檔中的一般 ADO.NET 提供者註冊。

儘管此 EF 在尋找要使用的 DbProviderFactory 時仍會使用其一般相依性解析機制。 預設解析程式會使用組態檔中的一般 ADO.NET 註冊,因此這通常是透明的。 但由於使用一般相依性解析機制,這表示 IDbDependencyResolver 可以用來解析 DbProviderFactory,即使尚未完成一般 ADO.NET 註冊也一般。

以這種方式解析 DbProviderFactory 有數個含意:

  • 使用程式碼型設定的應用程式可以在其 DbConfiguration 類別中新增呼叫,以註冊適當的 DbProviderFactory。 這特別適用于不想(或無法)使用任何檔案型組態的應用程式。
  • 您可以使用 ReplaceService 來包裝或取代服務,如上述包裝提供者 一節所述
  • 理論上,DbProviderServices 實作可以解析 DbProviderFactory。

執行上述任何一項動作的重點是,它們只會影響 EF 對 DbProviderFactory 的查閱。 其他非 EF 程式碼可能仍預期 ADO.NET 提供者會以正常方式註冊,如果找不到註冊,可能會失敗。 因此,DbProviderFactory 通常最好以一般 ADO.NET 方式註冊。

如果 EF 用來解析 DbProviderFactory,則也應該解析 IProviderInvariantName 和 IDbProviderFactoryResolver 服務。

IProviderInvariantName 是一項服務,可用來判斷指定 DbProviderFactory 類型的提供者不變異名稱。 此服務的預設實作會使用 ADO.NET 提供者註冊。 這表示如果 ADO.NET 提供者未以正常方式註冊,因為 EF 正在解析 DbProviderFactory,則也必須解析此服務。 請注意,使用 DbConfiguration.SetProviderFactory 方法時,會自動新增此服務的解析程式。

如上述提供者類型概觀 一節所述 ,IDbProviderFactoryResolver 可用來從指定的 Db連線ion 物件取得正確的 DbProviderFactory。 在 .NET 4 上執行時,此服務的預設實作會使用 ADO.NET 提供者註冊。 這表示如果 ADO.NET 提供者未以正常方式註冊,因為 EF 正在解析 DbProviderFactory,則也必須解析此服務。