Sdílet prostřednictvím


Model zprostředkovatele Entity Framework 6

Model zprostředkovatele Entity Framework umožňuje použití entity Framework s různými typy databázových serverů. Jeden zprostředkovatel lze například připojit, aby byl systém EF možné použít pro Microsoft SQL Server, zatímco jiný zprostředkovatel lze připojit, aby bylo možné ef použít pro Microsoft SQL Server Compact Edition. Zprostředkovatelé EF6, o které víme, najdete na stránce zprostředkovatelů Entity Framework.

Některé změny se vyžadovaly ve způsobu, jakým EF komunikuje s poskytovateli, aby bylo možné ef vydat v rámci opensourcové licence. Tyto změny vyžadují opětovné sestavení zprostředkovatelů EF vůči sestavením EF6 společně s novými mechanismy pro registraci zprostředkovatele.

Opětovné sestavení

S EF6 základní kód, který byl dříve součástí rozhraní .NET Framework, se nyní dodává jako vzdálené sestavení (OOB). Podrobnosti o tom, jak se vytvářejí aplikace s EF6, najdete na stránce Aktualizace aplikací pro EF6 . Zprostředkovatelé budou také muset znovu vytvořit pomocí těchto pokynů.

Přehled typů poskytovatelů

Zprostředkovatel EF je ve skutečnosti kolekce služeb specifických pro poskytovatele definované typy CLR, které tyto služby rozšiřují (pro základní třídu) nebo implementují (pro rozhraní). Dvě z těchto služeb jsou zásadní a nezbytné pro fungování EF vůbec. Jiné jsou volitelné a musí být implementovány pouze v případě, že je vyžadována konkrétní funkce nebo výchozí implementace těchto služeb nefungují pro konkrétní databázový server, na který se cílí.

Základní typy poskytovatelů

Dbproviderfactory

Ef závisí na typu odvozeného od System.Data.Common.DbProviderFactory pro provádění veškerého přístupu k databázi nízké úrovně. DbProviderFactory není ve skutečnosti součástí EF, ale je to třída v rozhraní .NET Framework, která slouží vstupnímu bodu pro ADO.NET zprostředkovatelů, které mohou být používány EF, jinými O/RM nebo přímo aplikací k získání instancí připojení, příkazů, parametrů a dalších ADO.NET abstrakce nezávislou na poskytovateli. Další informace o DbProviderFactory najdete v dokumentaci MSDN pro ADO.NET.

DbProviderServices

Ef závisí na tom, že má typ odvozený z DbProviderServices pro poskytování dalších funkcí potřebných EF nad funkčností, kterou již poskytuje poskytovatel ADO.NET. Ve starších verzích EF DbProviderServices byla součástí rozhraní .NET Framework a byla nalezena v oboru názvů System.Data.Common. Počínaje EF6 tato třída je nyní součástí EntityFramework.dll a je v system.Data.Entity.Core.Common obor názvů.

Další podrobnosti o základních funkcích implementace DbProviderServices najdete na webu MSDN. Všimněte si však, že v době psaní těchto informací se pro EF6 neaktualizuje, i když většina konceptů je stále platná. Sql Server a SQL Server Compact implementace DbProviderServices jsou také vráceny do opensourcového základu kódu a mohou sloužit jako užitečné odkazy pro jiné implementace.

Ve starších verzích EF DbProviderServices implementace, která se má použít, byla získána přímo od poskytovatele ADO.NET. To bylo provedeno přetypováním DbProviderFactory na IServiceProvider a volání GetService metoda. Tím se úzce propojil zprostředkovatel EF s DbProviderFactory. Tato spojka zablokovala přesunutí EF z rozhraní .NET Framework, a proto se pro EF6 tato úzká spojka odebrala a implementace DbProviderServices je nyní registrována přímo v konfiguračním souboru aplikace nebo v konfiguraci založené na kódu, jak je popsáno podrobněji v části Registrace DbProviderServices níže.

Další služby

Kromě základních služeb popsaných výše existuje také mnoho dalších služeb používaných EF, které jsou buď vždy, nebo někdy specifické pro poskytovatele. Výchozí implementace těchto služeb specifické pro zprostředkovatele je možné zadat implementací DbProviderServices. Aplikace mohou také přepsat implementace těchto služeb nebo poskytnout implementace, pokud dbProviderServices typ neposkytuje výchozí. Toto je podrobněji popsáno v části Řešení dalších služeb níže.

Níže jsou uvedené další typy služeb, které může poskytovatel zajímat. Další podrobnosti o jednotlivých těchto typech služeb najdete v dokumentaci k rozhraní API.

IDbExecutionStrategy

Jedná se o volitelnou službu, která umožňuje poskytovateli implementovat opakování nebo jiné chování při provádění dotazů a příkazů v databázi. Pokud není k dispozici žádná implementace, EF jednoduše spustí příkazy a rozšíří všechny vyvolané výjimky. Pro SQL Server se tato služba používá k poskytování zásad opakování, které je zvlášť užitečné při spouštění na cloudových databázových serverech, jako je SQL Azure.

IDb Připojení ionFactory

Jedná se o volitelnou službu, která umožňuje poskytovateli vytvářet objekty db Připojení ion podle konvence, pokud se přidělí pouze název databáze. Všimněte si, že zatímco tuto službu lze vyřešit implementací DbProviderServices, která existuje od EF 4.1 a lze ji také explicitně nastavit v konfiguračním souboru nebo v kódu. Poskytovatel bude mít možnost tuto službu vyřešit pouze v případě, že je zaregistrovaná jako výchozí poskytovatel (viz níže uvedený výchozí poskytovatel ) a pokud nebyla nastavena výchozí továrna pro připojení jinde.

DbSpatialServices

Toto je volitelná služba, která umožňuje poskytovateli přidat podporu geografických a geometrických prostorových typů. Aby aplikace mohla používat EF s prostorovými typy, musí být poskytována implementace této služby. DbSptialServices se požaduje dvěma způsoby. Nejprve se vyžaduje prostorové služby specifické pro zprostředkovatele pomocí objektu DbProviderInfo (který obsahuje invariantní název a token manifestu) jako klíč. Za druhé, DbSpatialServices lze požádat o bez klíče. Používá se k vyřešení "globálního poskytovatele prostorového prostoru", který se používá při vytváření samostatných typů DbGeography nebo DbGeometry.

MigrationSqlGenerator

Jedná se o volitelnou službu, která umožňuje použití migrací EF pro generování SQL, které se používají při vytváření a úpravách schémat databáze pomocí code First. K podpoře migrací se vyžaduje implementace. Pokud je k dispozici implementace, použije se také při vytváření databází pomocí inicializátorů databáze nebo Metody Database.Create.

Func<Db Připojení ion, string, HistoryContextFactory>

Jedná se o volitelnou službu, která umožňuje poskytovateli nakonfigurovat mapování HistoryContext na __MigrationHistory tabulku používanou migrací EF. HistoryContext je Code First DbContext a lze ho nakonfigurovat pomocí normálního fluent api pro změnu věcí, jako je název tabulky a specifikace mapování sloupců. Výchozí implementace této služby vrácená systémem souborů EF pro všechny zprostředkovatele může fungovat pro daný databázový server, pokud tento poskytovatel podporuje všechna výchozí mapování tabulek a sloupců. V takovém případě poskytovatel nemusí poskytovat implementaci této služby.

IDbProviderFactoryResolver

Jedná se o volitelnou službu pro získání správné DbProviderFactory z daného db Připojení ion objektu. Výchozí implementace této služby vrácená ef pro všechny poskytovatele je určena pro všechny poskytovatele. Pokud však běží na .NET 4, DbProviderFactory není veřejně přístupný z jednoho, pokud jeho Db Připojení ions. Ef proto k vyhledání shody používá několik heuristik pro vyhledávání registrovaných poskytovatelů. Je možné, že u některých poskytovatelů tyto heuristiky selžou a v takových situacích by poskytovatel měl poskytnout novou implementaci.

Registrace služby DbProviderServices

Implementace DbProviderServices, která se má použít, je možné zaregistrovat buď v konfiguračním souboru aplikace (app.config nebo web.config), nebo pomocí konfigurace založené na kódu. V obou případech registrace jako klíč používá invariantní název poskytovatele. To umožňuje registraci a použití více poskytovatelů v jedné aplikaci. Invariantní název použitý pro registrace EF je stejný jako invariantní název použitý pro registraci poskytovatele ADO.NET a připojovací řetězec. Například pro SQL Server se používá invariantní název System.Data.SqlClient.

Registrace konfiguračního souboru

Typ DbProviderServices, který se má použít, je registrován jako prvek zprostředkovatele v seznamu zprostředkovatelů oddílu entityFramework konfiguračního souboru aplikace. Příklad:

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

Řetězec typu musí být název sestavení kvalifikovaného typu implementace DbProviderServices, která se má použít.

Registrace založená na kódu

Počínaje poskytovateli EF6 je také možné zaregistrovat pomocí kódu. To umožňuje použití poskytovatele EF bez jakékoli změny konfiguračního souboru aplikace. Pokud chcete použít konfiguraci založenou na kódu, měla by aplikace vytvořit třídu DbConfiguration, jak je popsáno v dokumentaci ke konfiguraci založené na kódu. Konstruktor třídy DbConfiguration by pak měl volat SetProviderServices pro registraci zprostředkovatele EF. Příklad:

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

Řešení dalších služeb

Jak je uvedeno výše v části Přehled typů zprostředkovatele, lze také použít dbProviderServices třídy k řešení dalších služeb. To je možné, protože DbProviderServices implementuje IDbDependencyResolver a každý registrovaný typ DbProviderServices je přidán jako "výchozí překladač". Mechanismus IDbDpendencyResolver je podrobněji popsán v řešení závislostí. Není však nutné porozumět všem konceptům v této specifikaci, aby bylo možné vyřešit další služby poskytovatele.

Nejběžnějším způsobem, jak poskytovatel přeložit další služby, je volat DbProviderServices.AddDependencyResolver pro každou službu v konstruktoru DbProviderServices třídy. Například SqlProviderServices (zprostředkovatel EF pro SQL Server) má kód podobný tomuto pro inicializaci:

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;
        }));
}

Tento konstruktor používá následující pomocné třídy:

  • SingletonDependencyResolver: poskytuje jednoduchý způsob řešení služeb Singleton – to znamená služby, pro které se při každém zavolání GetService vrátí stejná instance. Přechodné služby se často registrují jako jednotonová továrna, která se použije k vytváření přechodných instancí na vyžádání.
  • ExecutionStrategyResolver: překladač specifický pro vrácení IExecutionStrategy implementace.

Místo použití DbProviderServices.AddDependencyResolver je také možné přepsat DbProviderServices.GetService a vyřešit další služby přímo. Tato metoda bude volána, když EF potřebuje službu definovanou určitým typem a v některých případech pro daný klíč. Metoda by měla vrátit službu, pokud může, nebo vrátit hodnotu null, aby se odhlasil od vrácení služby a místo toho umožnit jiné třídě, aby ji vyřešila. Pokud například chcete vyřešit výchozí objekt pro vytváření připojení, může kód v GetService vypadat nějak takto:

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

Objednávka registrace

Pokud je v konfiguračním souboru aplikace zaregistrováno více implementací DbProviderServices, přidají se jako sekundární překladače v pořadí, v jakém jsou uvedeny. Vzhledem k tomu, že se překladače vždy přidávají na začátek sekundárního řetězce překladače, znamená to, že poskytovatel na konci seznamu získá šanci přeložit závislosti před ostatními. (Zpočátku to může vypadat trochu protiintuitivně, ale dává smysl, pokud si představte, že si vezmete každého poskytovatele ze seznamu a naskládáte ho nad stávajícími poskytovateli.)

Toto řazení obvykle nezáleží, protože většina služeb poskytovatele je specifická pro poskytovatele a klíčuje ho invariantním názvem poskytovatele. U služeb, které nejsou klíči podle invariantního názvu zprostředkovatele nebo jiného klíče specifického pro konkrétního poskytovatele, se ale služba přeloží na základě tohoto řazení. Pokud například není explicitně nastaveno jinak, výchozí objekt pro vytváření připojení bude pocházet od nejvyššího poskytovatele v řetězci.

Další registrace konfiguračních souborů

Některé další služby poskytovatele popsané výše je možné explicitně zaregistrovat přímo v konfiguračním souboru aplikace. Po dokončení registrace v konfiguračním souboru se místo čehokoli vráceného metodou GetService implementace DbProviderServices.

Registrace výchozí továrny pro připojení

Počínaje EF5 balíček NuGet EntityFramework automaticky zaregistroval objekt pro vytváření připojení SQL Express nebo objekt pro vytváření připojení LocalDb v konfiguračním souboru.

Příklad:

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

Typ je název typu kvalifikovaného sestavení pro výchozí objekt pro vytváření připojení, který musí implementovat IDb Připojení ionFactory.

Doporučuje se, aby balíček NuGet zprostředkovatele nastavil výchozí objekt pro vytváření připojení tímto způsobem při instalaci. Níže najdete balíčky NuGet pro poskytovatele .

Další změny zprostředkovatele EF6

Změny prostorového zprostředkovatele

Poskytovatelé, kteří podporují prostorové typy, teď musí implementovat některé další metody tříd odvozených z DbSpatialDataReader:

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

Existují také nové asynchronní verze existujících metod, které se doporučuje přepsat jako výchozí implementace delegát na synchronní metody, a proto nespouštět asynchronně:

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

Nativní podpora enumerable.Contains

EF6 zavádí nový typ výrazu DbInExpression, který byl přidán k řešení problémů s výkonem při použití enumerable.Contains v dotazech LINQ. DbProviderManifest třída má novou virtuální metodu SupportsInExpression, která je volána EF k určení, zda zprostředkovatel zpracovává nový typ výrazu. Z důvodu kompatibility s existujícími implementacemi zprostředkovatele vrátí metoda hodnotu false. Aby bylo možné využít tohoto vylepšení, může zprostředkovatel EF6 přidat kód pro zpracování DbInExpression a přepsat SupportsInExpression, aby vrátil hodnotu true. Instanci DbInExpression lze vytvořit voláním DbExpressionBuilder.In metoda. Instance DbInExpression se skládá z DbExpression, obvykle představující sloupec tabulky, a seznam DbConstantExpression testovat shodu.

Balíčky NuGet pro poskytovatele

Jedním ze způsobů, jak zpřístupnit poskytovatele EF6, je uvolnit ho jako balíček NuGet. Použití balíčku NuGet má následující výhody:

  • K přidání registrace zprostředkovatele do konfiguračního souboru aplikace je snadné použít NuGet.
  • V konfiguračním souboru je možné provést další změny, které nastaví výchozí objekt pro vytváření připojení, aby připojení provedená konvencí používala zaregistrovaného zprostředkovatele.
  • NuGet zpracovává přidávání vazeb přesměrování, aby zprostředkovatel EF6 měl dál fungovat i po vydání nového balíčku EF.

Příkladem je balíček EntityFramework.SqlServerCompact, který je součástí opensourcového základu kódu. Tento balíček poskytuje dobrou šablonu pro vytváření balíčků NuGet zprostředkovatele EF.

Příkazy prostředí PowerShell

Při instalaci balíčku NuGet EntityFramework zaregistruje modul PowerShellu, který obsahuje dva příkazy, které jsou velmi užitečné pro balíčky zprostředkovatele:

  • Add-EFProvider přidá novou entitu pro zprostředkovatele v konfiguračním souboru cílového projektu a zajistí, že je na konci seznamu registrovaných poskytovatelů.
  • Add-EFDefault Připojení ionFactory buď přidá nebo aktualizuje výchozí registraci Připojení ionFactory v konfiguračním souboru cílového projektu.

Oba tyto příkazy se starají o přidání oddílu entityFramework do konfiguračního souboru a přidání kolekce zprostředkovatelů v případě potřeby.

Účelem je volat tyto příkazy ze skriptu NuGet install.ps1. Například install.ps1 pro poskytovatele SQL Compact vypadá nějak takto:

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>

Další informace o těchto příkazech lze získat pomocí rutiny get-help v okně konzoly Správce balíčků.

Zprostředkovatelé obtékání

Zprostředkovatel obtékání je EF nebo ADO.NET zprostředkovatel, který zabalí existujícího zprostředkovatele, aby ho rozšířil o další funkce, jako je profilace nebo trasování. Zprostředkovatelé obtékání je možné zaregistrovat běžným způsobem, ale často je vhodnější nastavit zprostředkovatele zabalení za běhu zachycením překladu služeb souvisejících s poskytovatelem. K tomu lze použít statickou událost OnLockingConfiguration třídy DbConfiguration.

OnLockingConfiguration se volá po určení, odkud se získá veškerá konfigurace EF pro doménu aplikace, ale před uzamčením pro použití. Při spuštění aplikace (před používáním EF) by aplikace měla pro tuto událost zaregistrovat obslužnou rutinu události. (Zvažujeme přidání podpory pro registraci této obslužné rutiny v konfiguračním souboru, ale zatím to není podporované.) Obslužná rutina události by pak měla volat ReplaceService pro každou službu, která musí být zabalena.

Pokud například chcete zabalit IDb Připojení ionFactory a DbProviderService, měla by se zaregistrovat obslužná rutina podobná této:

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

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

Služba, která byla vyřešena a měla by být zabalena společně s klíčem použitým k vyřešení služby, se předají obslužné rutině. Obslužná rutina pak může tuto službu zabalit a nahradit vrácenou službu zabalenou verzí.

Řešení DbProviderFactory s EF

DbProviderFactory je jedním ze základních typů zprostředkovatelů, které EF potřebuje, jak je popsáno v části Přehled typů poskytovatelů výše. Jak už bylo zmíněno, není to typ EF a registrace obvykle není součástí konfigurace EF, ale je to normální registrace poskytovatele ADO.NET v souboru machine.config nebo konfiguračním souboru aplikace.

I přes tento EF stále používá svůj normální mechanismus řešení závislostí při hledání DbProviderFactory, který se má použít. Výchozí překladač používá normální ADO.NET registraci v konfiguračních souborech, takže je to obvykle transparentní. Ale vzhledem k normálnímu mechanismu řešení závislostí se používá, znamená to, že IDbDependencyResolver lze použít k vyřešení DbProviderFactory i v případě, že normální ADO.NET registrace nebyla provedena.

Řešení DbProviderFactory tímto způsobem má několik důsledků:

  • Aplikace využívající konfiguraci založenou na kódu může přidat volání do své třídy DbConfiguration pro registraci příslušné DbProviderFactory. To je užitečné zejména pro aplikace, které nechtějí (nebo nemůžou) vůbec využívat žádnou konfiguraci založenou na souborech.
  • Službu lze zabalit nebo nahradit pomocí ReplaceService, jak je popsáno v části Poskytovatelé obtékání výše.
  • Teoreticky by implementace DbProviderServices mohla vyřešit DbProviderFactory.

Důležitým bodem, který je potřeba si uvědomit o provedení některé z těchto věcí, je, že ovlivní pouze vyhledávání DbProviderFactory podle EF. Jiný kód než EF může stále očekávat, že poskytovatel ADO.NET bude zaregistrovaný běžným způsobem a může selhat, pokud se registrace nenajde. Z tohoto důvodu je obvykle lepší, aby DbProviderFactory byl registrován v normálním ADO.NET způsobem.

Pokud se ef používá k překladu DbProviderFactory, měl by také přeložit IProviderInvariantName a IDbProviderFactoryResolver služby.

IProviderInvariantName je služba, která slouží k určení invariantního názvu zprostředkovatele pro daný typ DbProviderFactory. Výchozí implementace této služby používá registraci poskytovatele ADO.NET. To znamená, že pokud poskytovatel ADO.NET není zaregistrovaný normálním způsobem, protože dbProviderFactory se překládá pomocí EF, bude také nutné tuto službu vyřešit. Všimněte si, že překladač pro tuto službu je automaticky přidán při použití DbConfiguration.SetProviderFactory metoda.

Jak je popsáno v části Přehled typů zprostředkovatele výše, IDbProviderFactoryResolver se používá k získání správného DbProviderFactory z daného db Připojení ion objektu. Výchozí implementace této služby při spuštění v .NET 4 používá registraci poskytovatele ADO.NET. To znamená, že pokud poskytovatel ADO.NET není zaregistrovaný normálním způsobem, protože dbProviderFactory se překládá pomocí EF, bude také nutné tuto službu vyřešit.