Asynchronní dotaz a uložení

Poznámka:

Pouze EF6 a novější – Funkce, rozhraní API atd. popsané na této stránce byly představeny v Entity Framework 6. Pokud používáte starší verzi, některé nebo všechny informace nemusí být platné.

EF6 zavedl podporu asynchronního dotazu a uložení pomocí asynchronních a await klíčových slov , která byla zavedena v .NET 4.5. I když ne všechny aplikace můžou využívat asynchronní synchronizaci, je možné ji použít ke zlepšení odezvy klienta a škálovatelnosti serveru při zpracování dlouhotrvajících úloh, sítí nebo vstupně-výstupních úloh.

Kdy opravdu používat asynchronní

Účelem tohoto názorného postupu je zavést asynchronní koncepty způsobem, který usnadňuje sledování rozdílu mezi asynchronním a synchronním spuštěním programu. Tento názorný postup není určen k ilustraci žádného z klíčových scénářů, ve kterých asynchronní programování poskytuje výhody.

Asynchronní programování se primárně zaměřuje na uvolnění aktuálního spravovaného vlákna (vlákno s kódem .NET), aby fungovalo jinak, zatímco čeká na operaci, která nevyžaduje žádný výpočetní čas ze spravovaného vlákna. Zatímco například databázový stroj zpracovává dotaz, kód .NET nic dělat není.

V klientských aplikacích (WinForms, WPF atd.) lze aktuální vlákno použít k zachování odezvy uživatelského rozhraní při provedení asynchronní operace. V serverových aplikacích (ASP.NET atd.) lze vlákno použít ke zpracování jiných příchozích požadavků – to může snížit využití paměti nebo zvýšit propustnost serveru.

Ve většině aplikací používajících async nebude mít žádné znatelné výhody a dokonce může být škodlivé. Před potvrzením použití testů, profilace a běžného rozumu změřte dopad asynchronní synchronizace ve vašem konkrétním scénáři.

Tady je několik dalších zdrojů informací o asynchronním použití:

Vytvoření modelu

K vytvoření modelu a vygenerování databáze použijeme pracovní postup Code First, ale asynchronní funkce budou fungovat se všemi modely EF, včetně modelů vytvořených pomocí nástroje EF Designer.

  • Vytvoření konzolové aplikace a jeho volání AsyncDemo
  • Přidání balíčku NuGet EntityFramework
    • V Průzkumník řešení klikněte pravým tlačítkem na projekt AsyncDemo.
    • Vyberte Spravovat balíčky NuGet...
    • V dialogovém okně Spravovat balíčky NuGet vyberte kartu Online a zvolte balíček EntityFramework .
    • Klikněte na Nainstalovat.
  • Přidejte třídu Model.cs s následující implementací.
    using System.Collections.Generic;
    using System.Data.Entity;

    namespace AsyncDemo
    {
        public class BloggingContext : DbContext
        {
            public DbSet<Blog> Blogs { get; set; }
            public DbSet<Post> Posts { get; set; }
        }

        public class Blog
        {
            public int BlogId { get; set; }
            public string Name { get; set; }

            public virtual List<Post> Posts { get; set; }
        }

        public class Post
        {
            public int PostId { get; set; }
            public string Title { get; set; }
            public string Content { get; set; }

            public int BlogId { get; set; }
            public virtual Blog Blog { get; set; }
        }
    }

 

Vytvoření synchronního programu

Teď, když máme model EF, napište kód, který ho používá k provádění přístupu k datům.

  • Obsah souboru Program.cs nahraďte následujícím kódem.
    using System;
    using System.Linq;

    namespace AsyncDemo
    {
        class Program
        {
            static void Main(string[] args)
            {
                PerformDatabaseOperations();

                Console.WriteLine("Quote of the day");
                Console.WriteLine(" Don't worry about the world coming to an end today... ");
                Console.WriteLine(" It's already tomorrow in Australia.");

                Console.WriteLine();
                Console.WriteLine("Press any key to exit...");
                Console.ReadKey();
            }

            public static void PerformDatabaseOperations()
            {
                using (var db = new BloggingContext())
                {
                    // Create a new blog and save it
                    db.Blogs.Add(new Blog
                    {
                        Name = "Test Blog #" + (db.Blogs.Count() + 1)
                    });
                    Console.WriteLine("Calling SaveChanges.");
                    db.SaveChanges();
                    Console.WriteLine("SaveChanges completed.");

                    // Query for all blogs ordered by name
                    Console.WriteLine("Executing query.");
                    var blogs = (from b in db.Blogs
                                orderby b.Name
                                select b).ToList();

                    // Write all blogs out to Console
                    Console.WriteLine("Query completed with following results:");
                    foreach (var blog in blogs)
                    {
                        Console.WriteLine(" " + blog.Name);
                    }
                }
            }
        }
    }

Tento kód volá metoduPerformDatabaseOperations, která uloží nový blog do databáze a pak načte všechny blogy z databáze a vytiskne je do konzoly. Potom program napíše citát dne do konzoly.

Vzhledem k tomu, že kód je synchronní, můžeme při spuštění programu sledovat následující tok spuštění:

  1. SaveChanges začne odesílat nový blog do databáze.
  2. SaveChanges Dokončí
  3. Dotaz na všechny blogy se odešle do databáze.
  4. Vrácení dotazu a výsledky se zapisují do konzoly.
  5. Citace dne se zapíše do konzoly.

Sync Output 

 

Vytvoření asynchronního

Teď, když máme náš program spuštěný, můžeme začít používat nové asynchronní a await klíčová slova. Provedli jsme následující změny souboru Program.cs.

  1. Řádek 2: Příkaz using pro System.Data.Entity obor názvů nám poskytuje přístup k asynchronním rozšiřujícím metodám EF.
  2. Řádek 4: Příkaz using pro System.Threading.Tasks obor názvů nám umožňuje použít Task typ.
  3. Řádek 12 a 18: Zaznamenáváme jako úkol, který sleduje průběh PerformSomeDatabaseOperations (řádek 12) a pak blokuje provádění programu pro tento úkol, jakmile se dokončí všechna práce programu (řádek 18).
  4. Řádek 25: Aktualizovali jsme, abychom byli označeni jako async a vrátili PerformSomeDatabaseOperations hodnotu Task.
  5. Řádek 35: Nyní voláme asynchronní verzi SaveChanges a čekáme na dokončení.
  6. Řádek 42: Nyní voláme asynchronní verzi ToList a čekáme na výsledek.

Úplný seznam dostupných rozšiřujících metod v System.Data.Entity oboru názvů najdete ve QueryableExtensions třídě. Budete také muset přidat using System.Data.Entity do příkazů using.

    using System;
    using System.Data.Entity;
    using System.Linq;
    using System.Threading.Tasks;

    namespace AsyncDemo
    {
        class Program
        {
            static void Main(string[] args)
            {
                var task = PerformDatabaseOperations();

                Console.WriteLine("Quote of the day");
                Console.WriteLine(" Don't worry about the world coming to an end today... ");
                Console.WriteLine(" It's already tomorrow in Australia.");

                task.Wait();

                Console.WriteLine();
                Console.WriteLine("Press any key to exit...");
                Console.ReadKey();
            }

            public static async Task PerformDatabaseOperations()
            {
                using (var db = new BloggingContext())
                {
                    // Create a new blog and save it
                    db.Blogs.Add(new Blog
                    {
                        Name = "Test Blog #" + (db.Blogs.Count() + 1)
                    });
                    Console.WriteLine("Calling SaveChanges.");
                    await db.SaveChangesAsync();
                    Console.WriteLine("SaveChanges completed.");

                    // Query for all blogs ordered by name
                    Console.WriteLine("Executing query.");
                    var blogs = await (from b in db.Blogs
                                orderby b.Name
                                select b).ToListAsync();

                    // Write all blogs out to Console
                    Console.WriteLine("Query completed with following results:");
                    foreach (var blog in blogs)
                    {
                        Console.WriteLine(" - " + blog.Name);
                    }
                }
            }
        }
    }

Teď, když je kód asynchronní, můžeme při spuštění programu sledovat jiný tok provádění:

  1. SaveChanges začne odesílat nový blog do databáze.
    Jakmile se příkaz odešle do databáze, není potřeba žádný další výpočetní čas v aktuálním spravovaném vlákně. Metoda PerformDatabaseOperations se vrátí (i když se nedokončila provádění) a tok programu v metodě Main pokračuje.
  2. Citace dne se zapíše do konzoly.
    Vzhledem k tomu, že v metodě Main není k dispozici žádná další práce, spravované vlákno je blokováno volání Wait , dokud se operace databáze nedokončí. Po dokončení se provede zbytek naší PerformDatabaseOperations operace.
  3. SaveChanges Dokončí
  4. Dotaz na všechny blogy se odešle do databáze.
    Spravované vlákno je opět možné provádět jiné práce, zatímco dotaz je zpracován v databázi. Vzhledem k tomu, že se dokončilo všechna ostatní spuštění, vlákno se ale zastaví při volání Wait.
  5. Vrácení dotazu a výsledky se zapisují do konzoly.

Async Output 

 

Vysuďte si to.

Viděli jsme, jak snadné je používat asynchronní metody EF. I když u jednoduché konzolové aplikace nemusí být výhody asynchronního přístupu úplně zřejmé, můžete použít stejné strategie v situacích, kdy dlouhotrvající nebo síťové aktivity můžou aplikaci jinak blokovat nebo způsobit, že velký počet vláken zvýší nároky na paměť.