Sdílet prostřednictvím


Klientská knihovna Elastic Database s Entity Frameworkem

Platí pro: Azure SQL Database

Tento dokument ukazuje změny v aplikaci Entity Framework, které jsou potřeba k integraci s nástroji elastické databáze. Zaměřuje se na vytváření správy mapování horizontálních oddílů a směrování závislého na datech pomocí přístupu Entity Framework Code First . Kurz Code First – Nová databáze pro EF slouží jako spuštěný příklad v celém tomto dokumentu. Ukázkový kód, který tento dokument doprovází, je součástí sady ukázek nástrojů elastické databáze v ukázkách editoru Visual Studio Code.

Poznámka:

Tento článek se nevztahuje na Entity Framework Core (EF Core).

Stažení a spuštění ukázkového kódu

Stažení kódu pro tento článek:

  • Vyžaduje se Visual Studio 2012 nebo novější.
  • Stáhněte si ukázku integrace elastické databáze pro Azure SQL – Entity Framework. Rozbalte ukázku do umístění podle vašeho výběru.
  • Spusťte Visual Studio.
  • V sadě Visual Studio vyberte Soubor –> Otevřít projekt nebo řešení.
  • V dialogovém okně Otevřít projekt přejděte na ukázku, kterou jste stáhli, a výběrem EntityFrameworkCodeFirst.sln ukázku otevřete.

Pokud chcete ukázku spustit, musíte ve službě Azure SQL Database vytvořit tři prázdné databáze:

  • Databáze Správce mapování horizontálních oddílů
  • Databáze horizontálních oddílů 1
  • Databáze horizontálních oddílů 2

Po vytvoření těchto databází vyplňte držitelé míst v Program.cs názvem vašeho serveru, názvy databází a přihlašovací údaje pro připojení k databázím. Sestavte řešení v sadě Visual Studio. Visual Studio stáhne požadované balíčky NuGet pro klientskou knihovnu elastické databáze, Entity Framework a zpracování přechodných chyb v rámci procesu sestavení. Ujistěte se, že je pro vaše řešení povolené obnovení balíčků NuGet. Toto nastavení můžete povolit tak, že kliknete pravým tlačítkem na soubor řešení v Průzkumník řešení sady Visual Studio.

Pracovní postupy Entity Frameworku

Vývojáři entity Framework spoléhají na jeden z následujících čtyř pracovních postupů při sestavování aplikací a k zajištění trvalosti objektů aplikací:

  • Code First (Nová databáze):: Vývojář EF vytvoří model v kódu aplikace a pak z ní vygeneruje databázi EF.
  • Code First (existující databáze):Vývojář umožňuje EF vygenerovat kód aplikace pro model z existující databáze.
  • Nejprve model: Vývojář vytvoří model v návrháři EF a pak EF vytvoří databázi z modelu.
  • Nejprve databáze: Vývojář používá nástroje EF k odvození modelu z existující databáze.

Všechny tyto přístupy využívají třídu DbContext k transparentní správě připojení k databázi a schématu databáze pro aplikaci. Různé konstruktory základní třídy DbContext umožňují různé úrovně kontroly nad vytvářením připojení, spouštěním databáze a vytvořením schématu. K problémům dochází především ze skutečnosti, že správa připojení k databázi poskytovaná ef protíná s možnostmi správy připojení rozhraní směrování závislých na datech poskytovaných klientskou knihovnou elastické databáze.

Předpoklady pro nástroje elastické databáze

Definice termínů najdete v glosáři nástrojů elastické databáze.

S klientskou knihovnou elastické databáze definujete oddíly aplikačních dat označovaných jako shardlety. Shardlety jsou identifikovány klíčem horizontálního dělení a jsou mapovány na konkrétní databáze. Aplikace může mít tolik databází, kolik potřebujete, a distribuovat shardlety tak, aby poskytovala dostatečnou kapacitu nebo výkon vzhledem k aktuálním obchodním požadavkům. Mapování hodnot klíče horizontálního dělení na databáze je uloženo mapou horizontálních oddílů, kterou poskytuje rozhraní API klienta elastické databáze. Tato funkce se zkráceně nazývá Správa mapování horizontálních oddílů nebo SMM. Mapa horizontálních oddílů slouží také jako zprostředkovatel připojení databáze pro požadavky, které mají klíč horizontálního dělení. Tato funkce se označuje jako směrování závislé na datech.

Správce mapování horizontálních oddílů chrání uživatele před nekonzistentními zobrazeními na data shardletu, ke kterým může dojít, když dochází k souběžným operacím správy horizontálních oddílů (například přemístění dat z jednoho horizontálního oddílu do jiného). Provedete to tak, že mapy horizontálních oddílů spravované klientskou knihovnou zprostředkují připojení databáze pro aplikaci. To umožňuje funkci mapování horizontálních oddílů automaticky ukončovat připojení databáze, když operace správy horizontálních oddílů můžou mít vliv na shardlet, pro který bylo připojení vytvořeno. Tento přístup se musí integrovat s některými funkcemi EF, jako je například vytvoření nových připojení z existujícího systému, aby se zkontrolovala existence databáze. Obecně platí, že standardní konstruktory DbContext fungují spolehlivě pouze pro uzavřená databázová připojení, která lze bezpečně klonovat pro práci EF. Principem návrhu elastické databáze je místo toho pouze zprostředkování otevřených připojení. Možná si myslíte, že tento problém může vyřešit zavření připojení zprostředkované klientskou knihovnou předtím, než ho předáte ef DbContext. Když ale připojení zavřete a spoléháte se na ef a znovu ho otevřete, jeden z nich předepře ověření a kontroly konzistence prováděné knihovnou. Funkce migrace v EF však tato připojení používá ke správě základního schématu databáze způsobem, který je pro aplikaci transparentní. V ideálním případě zachováte a zkombinujete všechny tyto funkce z klientské knihovny elastické databáze i ef ve stejné aplikaci. Následující část popisuje tyto vlastnosti a požadavky podrobněji.

Požadavky

Při práci s klientskou knihovnou elastické databáze i rozhraními API entity Framework chcete zachovat následující vlastnosti:

  • Horizontální navýšení kapacity: Přidání nebo odebrání databází z datové vrstvy horizontálně dělené aplikace podle potřeby pro požadavky aplikace na kapacitu. To znamená kontrolu nad vytvářením a odstraňováním databází a pomocí rozhraní API správce mapování horizontálních oddílů elastické databáze ke správě databází a mapování shardletů.
  • Konzistence: Aplikace využívá horizontální dělení a používá možnosti směrování závislé na datech klientské knihovny. Aby nedošlo k poškození nebo nesprávnému výsledku dotazu, zprostředkovávají se připojení prostřednictvím správce mapování horizontálních oddílů. To také zachovává ověřování a konzistenci.
  • První kód: Zachování pohodlí kódu EF první paradigmatu. V Code First jsou třídy v aplikaci mapovány transparentně na základní databázové struktury. Kód aplikace komunikuje se sadami DbSet, které maskují většinu aspektů souvisejících se zpracováním podkladové databáze.
  • Schéma: Entity Framework zpracovává počáteční vytvoření schématu databáze a následný vývoj schématu prostřednictvím migrací. Díky zachování těchto funkcí je přizpůsobení aplikace snadné, jak se data vyvíjejí.

Následující doprovodné materiály dávají pokyn, jak tyto požadavky splnit pro aplikace Code First pomocí nástrojů elastické databáze.

Směrování závislé na datech pomocí EF DbContext

Připojení k databázi pomocí Entity Framework se obvykle spravují prostřednictvím podtříd dbContext. Vytvořte tyto podtřídy odvozením z DbContext. Tady definujete dbSets, které implementují kolekce objektů CLR založené na databázi pro vaši aplikaci. V kontextu směrování závislého nadatech

  • Databáze již existuje a je zaregistrovaná v mapě horizontálních oddílů elastické databáze.
  • Schéma aplikace již bylo nasazeno do databáze (vysvětleno níže).
  • Mapování horizontálních oddílů zprostředkovávají připojení směrování závislá na datech k databázi.

Integrace DbContexts se směrováním závislým na datech pro horizontální navýšení kapacity:

  1. Vytvořte fyzická připojení k databázi prostřednictvím klientských rozhraní elastické databáze správce map horizontálních oddílů.
  2. Zabalení připojení podtřídou DbContext
  3. Předejte připojení do základních tříd DbContext , aby se zajistilo, že veškeré zpracování na straně EF proběhne také.

Tento přístup ilustruje následující příklad kódu. (Tento kód je také v doprovodném projektu sady Visual Studio)

public class ElasticScaleContext<T> : DbContext
{
public DbSet<Blog> Blogs { get; set; }
...

    // C'tor for data-dependent routing. This call opens a validated connection
    // routed to the proper shard by the shard map manager.
    // Note that the base class c'tor call fails for an open connection
    // if migrations need to be done and SQL credentials are used. This is the reason for the
    // separation of c'tors into the data-dependent routing case (this c'tor) and the internal c'tor for new shards.
    public ElasticScaleContext(ShardMap shardMap, T shardingKey, string connectionStr)
        : base(CreateDDRConnection(shardMap, shardingKey, connectionStr),
        true /* contextOwnsConnection */)
    {
    }

    // Only static methods are allowed in calls into base class c'tors.
    private static DbConnection CreateDDRConnection(
    ShardMap shardMap,
    T shardingKey,
    string connectionStr)
    {
        // No initialization
        Database.SetInitializer<ElasticScaleContext<T>>(null);

        // Ask shard map to broker a validated connection for the given key
        SqlConnection conn = shardMap.OpenConnectionForKey<T>
                            (shardingKey, connectionStr, ConnectionOptions.Validate);
        return conn;
    }

Hlavní body

  • Nový konstruktor nahrazuje výchozí konstruktor v podtřídě DbContext.

  • Nový konstruktor přebírá argumenty potřebné pro směrování závislé na datech prostřednictvím klientské knihovny elastické databáze:

    • mapování horizontálních oddílů pro přístup k rozhraním směrování závislým na datech,
    • klíč horizontálního dělení k identifikaci shardletu,
    • připojovací řetězec s přihlašovacími údaji pro připojení směrování závislého na datech k horizontálnímu oddílu.
  • Volání konstruktoru základní třídy přebírá obejití do statické metody, která provádí všechny kroky nezbytné pro směrování závislé na datech.

    • K navázání otevřeného připojení používá volání OpenConnectionForKey klientských rozhraní elastické databáze na mapě horizontálních oddílů.
    • Mapa horizontálních oddílů vytvoří otevřené připojení k horizontálnímu oddílu, který obsahuje shardlet pro daný klíč horizontálního dělení.
    • Toto otevřené připojení se předá zpět do konstruktoru základní třídy DbContext, aby bylo možné označit, že toto připojení má ef používat místo automatického vytvoření nového připojení EF. Tímto způsobem bylo připojení označené klientským rozhraním API elastické databáze, aby bylo možné zaručit konzistenci v rámci operací správy mapování horizontálních oddílů.

Místo výchozího konstruktoru v kódu použijte nový konstruktor pro podtřídu DbContext. Zde je příklad:

// Create and save a new blog.

Console.Write("Enter a name for a new blog: ");
var name = Console.ReadLine();

using (var db = new ElasticScaleContext<int>(
                        sharding.ShardMap,  
                        tenantId1,  
                        connStrBldr.ConnectionString))
{
    var blog = new Blog { Name = name };
    db.Blogs.Add(blog);
    db.SaveChanges();

    // Display all Blogs for tenant 1
    var query = from b in db.Blogs
                orderby b.Name
                select b;
    …
}

Nový konstruktor otevře připojení k horizontálnímu oddílu, který obsahuje data pro shardlet identifikovanou hodnotou tenantid1. Kód v bloku using zůstává beze změny pro přístup k dbSet pro blogy pomocí EF v horizontálním oddílu pro tenantid1. Tato změna sémantiky kódu v bloku using, aby všechny databázové operace byly nyní vymezeny na jeden horizontální oddíl, ve kterém je tenantid1 zachován. Například dotaz LINQ na blogy DbSet by vrátil pouze blogy uložené v aktuálním horizontálním oddílu, ale ne ty uložené v jiných horizontálních oddílech.

Zpracování přechodných chyb

Tým Microsoft Patterns &Practices publikoval blok aplikace pro zpracování přechodných chyb. Knihovna se používá s klientskou knihovnou elastického škálování v kombinaci s EF. Zajistěte však, aby se jakákoli přechodná výjimka vrátila na místo, kde můžete zajistit, aby se nový konstruktor používal po přechodné chybě, aby se všechny nové pokusy o připojení provedly pomocí konstruktorů, které jste upravili. V opačném případě není zaručeno připojení ke správnému horizontálnímu oddílu a neexistuje žádné záruky, že se připojení zachová, protože dojde ke změnám mapy horizontálních oddílů.

Následující ukázka kódu ukazuje, jak je možné použít zásadu opakování SQL kolem nových konstruktorů podtřídy DbContext :

SqlDatabaseUtils.SqlRetryPolicy.ExecuteAction(() =>
{
    using (var db = new ElasticScaleContext<int>(
                            sharding.ShardMap,  
                            tenantId1,  
                            connStrBldr.ConnectionString))
        {
                var blog = new Blog { Name = name };
                db.Blogs.Add(blog);
                db.SaveChanges();
        …
        }
    });

SqlDatabaseUtils.SqlRetryPolicy v kódu výše je definován jako SqlDatabaseTransientErrorDetectionStrategy s počtem opakování 10 a 5 sekund čekání mezi opakováními. Tento přístup je podobný pokynům pro ef a uživatelem iniciované transakce (viz omezení pro strategie opakování provádění (EF6 atd.). Obě situace vyžadují, aby program aplikace řídí obor, na který se přechodná výjimka vrací: k opětovnému otevření transakce, nebo (jak je znázorněno) znovu vytvořit kontext z správného konstruktoru, který používá klientskou knihovnu elastické databáze.

Nutnost řídit, kde nás přechodné výjimky přebírají zpět v oboru, také brání použití integrovaného sqlAzureExecutionStrategy , který je součástí EF. SqlAzureExecutionStrategy by znovu otevřel připojení, ale nepoužívá OpenConnectionForKey , a proto obejití všech ověření, které se provádí jako součást volání OpenConnectionForKey . Místo toho vzorový kód používá integrovanou funkci DefaultExecutionStrategy , která je součástí EF. Na rozdíl od SqlAzureExecutionStrategy funguje správně v kombinaci se zásadou opakování zpracování přechodných chyb. Zásada spouštění je nastavena ve třídě ElasticScaleDbConfiguration . Všimněte si, že jsme se rozhodli nepoužívat DefaultSqlExecutionStrategy , protože navrhuje použití SqlAzureExecutionStrategy , pokud dojde k přechodným výjimkám – což by vedlo k nesprávnému chování, jak je popsáno. Další informace o různých zásadách opakování a ef najdete v tématu Odolnost připojení v EF.

Přepíše konstruktor

Výše uvedené příklady kódu ilustrují výchozí přepisování konstruktorů vyžadovaných pro vaši aplikaci, aby bylo možné použít směrování závislé na datech s Entity Frameworkem. Následující tabulka generalizuje tento přístup k ostatním konstruktorům.

Aktuální konstruktor Přepsaný konstruktor pro data Základní konstruktor Notes
MyContext() ElasticScaleContext(ShardMap, TKey) DbContext(DbConnection, bool) Připojení musí být funkcí mapy horizontálních oddílů a klíče směrování závislého na datech. K zprostředkování připojení je potřeba provést automatické vytvoření připojení ef a místo toho použít mapu horizontálních oddílů ke zprostředkování připojení.
MyContext(řetězec) ElasticScaleContext(ShardMap, TKey) DbContext(DbConnection, bool) Připojení je funkce mapování horizontálních oddílů a klíče směrování závislého na datech. Pevný název databáze nebo připojovací řetězec nefunguje, protože ověřování podle mapování horizontálních oddílů nefunguje.
MyContext(DbCompiledModel) ElasticScaleContext(ShardMap, TKey, DbCompiledModel) DbContext(DbConnection, DbCompiledModel, bool) Připojení se vytvoří pro danou mapu horizontálních oddílů a klíč horizontálního dělení pomocí poskytnutého modelu. Zkompilovaný model se předává do základního konstruktoru.
MyContext(DbConnection, bool) ElasticScaleContext(ShardMap, TKey, bool) DbContext(DbConnection, bool) Připojení musí být odvozeno z mapy horizontálních oddílů a klíče. Nelze jej zadat jako vstup (pokud tento vstup ještě nepoužíval mapování horizontálních oddílů a klíč). Logická hodnota je předána dál.
MyContext(řetězec, DbCompiledModel) ElasticScaleContext(ShardMap, TKey, DbCompiledModel) DbContext(DbConnection, DbCompiledModel, bool) Připojení musí být odvozeno z mapy horizontálních oddílů a klíče. Nelze jej zadat jako vstup (pokud tento vstup nepoužíval mapování horizontálních oddílů a klíč). Zkompilovaný model se předá.
MyContext(ObjectContext, bool) ElasticScaleContext(ShardMap, TKey, ObjectContext, bool) DbContext(ObjectContext, bool) Nový konstruktor musí zajistit, aby jakékoli připojení v ObjectContext předané jako vstup bylo znovu směrováno do připojení spravovaného elastickým škálováním. Podrobná diskuze o ObjectContexts je nad rámec tohoto dokumentu.
MyContext(DbConnection, DbCompiledModel, bool) ElasticScaleContext(ShardMap, TKey, DbCompiledModel, bool) DbContext(DbConnection, DbCompiledModel, bool); Připojení musí být odvozeno z mapy horizontálních oddílů a klíče. Připojení nelze zadat jako vstup (pokud tento vstup ještě nepoužíval mapování horizontálních oddílů a klíč). Model a logická hodnota se předávají konstruktoru základní třídy.

Nasazení schématu horizontálního dělení prostřednictvím migrací EF

Automatická správa schématu je pohodlí poskytovaná rozhraním Entity Framework. V kontextu aplikací využívajících nástroje elastické databáze chcete zachovat tuto funkci, abyste při přidání databází do horizontálně dělené aplikace automaticky zřídili schéma pro nově vytvořené horizontální oddíly. Primárním případem použití je zvýšení kapacity datové vrstvy pro horizontálně dělené aplikace využívající EF. Spoléhání na možnosti EF pro správu schématu snižuje úsilí správy databáze pomocí horizontálně dělené aplikace založené na EF.

Nasazení schématu prostřednictvím migrací EF funguje nejlépe u neotevřených připojení. To je na rozdíl od scénáře směrování závislého na datech, které závisí na otevřeném připojení poskytovaném klientským rozhraním API elastické databáze. Dalším rozdílem je požadavek na konzistenci: I když je žádoucí zajistit konzistenci pro všechna připojení směrování závislá na datech k ochraně před souběžnou manipulací s mapováním horizontálních oddílů, nejedná se o počáteční nasazení schématu do nové databáze, která ještě nebyla zaregistrovaná v mapě horizontálních oddílů, a ještě nebyla přidělena k uchovávání shardletů. Proto můžete spoléhat na běžná databázová připojení pro tento scénář, a ne na směrování závislé na datech.

To vede k přístupu, kdy nasazení schématu prostřednictvím migrací EF je úzce spojeno s registrací nové databáze jako horizontálního oddílu v mapě horizontálních oddílů aplikace. To závisí na následujících požadavcích:

  • Databáze již byla vytvořena.
  • Databáze je prázdná – neobsahuje žádné uživatelské schéma a žádná uživatelská data.
  • Databáze ještě není přístupná prostřednictvím klientských rozhraní API elastické databáze pro směrování závislé na datech.

S těmito požadavky můžete vytvořit běžnou neotevřenou službu SqlConnection , která zahájí migrace EF pro nasazení schématu. Tento přístup ilustruje následující ukázka kódu.

// Enter a new shard - i.e. an empty database - to the shard map, allocate a first tenant to it  
// and kick off EF initialization of the database to deploy schema

public void RegisterNewShard(string server, string database, string connStr, int key)
{

    Shard shard = this.ShardMap.CreateShard(new ShardLocation(server, database));

    SqlConnectionStringBuilder connStrBldr = new SqlConnectionStringBuilder(connStr);
    connStrBldr.DataSource = server;
    connStrBldr.InitialCatalog = database;

    // Go into a DbContext to trigger migrations and schema deployment for the new shard.
    // This requires an un-opened connection.
    using (var db = new ElasticScaleContext<int>(connStrBldr.ConnectionString))
    {
        // Run a query to engage EF migrations
        (from b in db.Blogs
            select b).Count();
    }

    // Register the mapping of the tenant to the shard in the shard map.
    // After this step, data-dependent routing on the shard map can be used

    this.ShardMap.CreatePointMapping(key, shard);
}

Tato ukázka ukazuje metodu RegisterNewShard , která registruje horizontální oddíl v mapě horizontálních oddílů, nasadí schéma prostřednictvím migrací EF a uloží mapování klíče horizontálního dělení na horizontální oddíl. Spoléhá na konstruktor podtřídy DbContext (ElasticScaleContext v ukázce), který jako vstup přebírá připojovací řetězec SQL. Kód tohoto konstruktoru je přímočarý, jak ukazuje následující příklad:

// C'tor to deploy schema and migrations to a new shard
protected internal ElasticScaleContext(string connectionString)
    : base(SetInitializerForConnection(connectionString))
{
}

// Only static methods are allowed in calls into base class c'tors
private static string SetInitializerForConnection(string connectionString)
{
    // You want existence checks so that the schema can get deployed
    Database.SetInitializer<ElasticScaleContext<T>>(
new CreateDatabaseIfNotExists<ElasticScaleContext<T>>());

    return connectionString;
}

Jeden mohl použít verzi konstruktoru zděděného ze základní třídy. Kód ale musí zajistit, aby se při připojování použil výchozí inicializátor ef. Proto krátký detour do statické metody před voláním do konstruktoru základní třídy s připojovací řetězec. Všimněte si, že registrace horizontálních oddílů by se měla spouštět v jiné doméně nebo procesu aplikace, aby se zajistilo, že nastavení inicializátoru pro EF není v konfliktu.

Omezení

Přístupy popsané v tomto dokumentu zahrnují několik omezení:

  • Aplikace EF, které používají LocalDb , musí nejprve migrovat do běžné databáze SQL Serveru před použitím klientské knihovny elastické databáze. Horizontální navýšení kapacity aplikace prostřednictvím horizontálního dělení pomocí elastického škálování není u LocalDb možné. Mějte na paměti, že vývoj může stále používat LocalDb.
  • Všechny změny aplikace, které naznačují, že změny schématu databáze musí projít migrací EF ve všech horizontálních oddílech. Ukázkový kód pro tento dokument neukazuje, jak to provést. Zvažte použití update-Database s parametrem ConnectionString k iteraci nad všemi horizontálními oddíly; nebo extrahujte skript T-SQL pro čekající migraci pomocí update-Database s parametrem -Script a použijte skript T-SQL na horizontální oddíly.
  • Vzhledem k požadavku se předpokládá, že veškeré zpracování databáze je obsaženo v jednom horizontálním oddílu, jak je identifikováno klíčem horizontálního dělení poskytnutého požadavkem. Tento předpoklad ale nemusí být vždy pravdivý. Pokud například není možné zpřístupnit klíč horizontálního dělení. K vyřešení toho poskytuje klientská knihovna třídu MultiShardQuery , která implementuje abstrakci připojení pro dotazování na několik horizontálních oddílů. Učení se používat MultiShardQuery v kombinaci s EF je nad rámec tohoto dokumentu.

Závěr

Prostřednictvím kroků popsaných v tomto dokumentu můžou aplikace EF používat schopnost klientské knihovny elastické databáze pro směrování závislé na datech refaktoringem konstruktorů podtříd DbContext používaných v aplikaci EF. Tím se omezí změny vyžadované na těch místech, kde již existují třídy DbContext . Kromě toho můžou aplikace EF dál těžit z automatického nasazení schématu tím, že zkombinují kroky, které vyvolají potřebné migrace EF, s registrací nových horizontálních oddílů a mapování v mapě horizontálních oddílů.

Ještě nepoužíváte nástroje elastické databáze? Podívejte se na naši příručku Začínáme. Pokud máte dotazy, kontaktujte nás na stránce otázek Microsoft Q&A pro SLUŽBU SQL Database a žádosti o funkce, přidejte nové nápady nebo hlasujte pro stávající nápady ve fóru pro zpětnou vazbu ke službě SQL Database.