Udostępnij za pośrednictwem


Zapytanie asynchroniczne i zapisywanie

Uwaga

Tylko rozwiązanie EF6 i nowsze wersje — Funkcje, interfejsy API itp. omówione na tej stronie zostały wprowadzone w rozwiązaniu Entity Framework 6. Jeśli korzystasz ze starszej wersji, niektóre lub wszystkie podane informacje nie mają zastosowania.

Platforma EF6 wprowadziła obsługę asynchronicznego zapytania i zapisywania przy użyciu słów kluczowych asynchronicznych i await, które zostały wprowadzone na platformie .NET 4.5. Chociaż nie wszystkie aplikacje mogą korzystać z asynchronii, może służyć do poprawy czasu odpowiedzi klienta i skalowalności serwera podczas obsługi długotrwałych zadań związanych z siecią lub we/wy.

Kiedy naprawdę używać asynchronicznego

Celem tego przewodnika jest wprowadzenie pojęć asynchronicznych w sposób, który ułatwia obserwowanie różnicy między asynchronicznym i synchronicznym wykonywaniem programu. Ten przewodnik nie ma na celu zilustrowania żadnego z kluczowych scenariuszy, w których programowanie asynchroniczne zapewnia korzyści.

Programowanie asynchroniczne koncentruje się przede wszystkim na zwalnianiu bieżącego zarządzanego wątku (wątku z uruchomionym kodem platformy .NET) w celu wykonania innej pracy podczas oczekiwania na operację, która nie wymaga czasu obliczeniowego z zarządzanego wątku. Na przykład aparat bazy danych przetwarza zapytanie, ale nie ma nic wspólnego z kodem platformy .NET.

W aplikacjach klienckich (WinForms, WPF itp.) bieżący wątek może służyć do zapewnienia czasu reakcji interfejsu użytkownika podczas wykonywania operacji asynchronicznych. W aplikacjach serwerowych (ASP.NET itp.) wątek może służyć do przetwarzania innych żądań przychodzących — może to zmniejszyć użycie pamięci i/lub zwiększyć przepływność serwera.

W większości aplikacji korzystających z async nie będą miały zauważalnych korzyści, a nawet mogą być szkodliwe. Użyj testów, profilowania i zdrowego rozsądku, aby zmierzyć wpływ asynchronicznego działania w konkretnym scenariuszu przed jego zatwierdzeniem.

Poniżej przedstawiono kilka dodatkowych zasobów, aby dowiedzieć się więcej na temat asynchronicznego:

Tworzenie modelu

Użyjemy przepływu pracy Code First, aby utworzyć nasz model i wygenerować bazę danych, jednak funkcja asynchroniczna będzie działać ze wszystkimi modelami EF, w tym z modelami utworzonymi przy użyciu platformy EF Projektant.

  • Tworzenie aplikacji konsolowej i wywoływanie jej asyncDemo
  • Dodawanie pakietu NuGet EntityFramework
    • W Eksplorator rozwiązań kliknij prawym przyciskiem myszy projekt AsyncDemo
    • Wybierz pozycję Zarządzaj pakietami NuGet...
    • W oknie dialogowym Zarządzanie pakietami NuGet wybierz kartę Online i wybierz pakiet EntityFramework
    • Kliknij pozycję Zainstaluj
  • Dodaj klasę Model.cs z następującą implementacją
    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; }
        }
    }

 

Tworzenie programu synchronicznego

Teraz, gdy mamy model EF, napiszmy kod, który używa go do wykonywania dostępu do danych.

  • Zastąp zawartość pliku Program.cs następującym kodem
    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);
                    }
                }
            }
        }
    }

Ten kod wywołuje metodę PerformDatabaseOperations , która zapisuje nowy blog w bazie danych, a następnie pobiera wszystkie blogi z bazy danych i drukuje je w konsoli. Następnie program zapisuje cudzysłów dnia w konsoli.

Ponieważ kod jest synchroniczny, możemy obserwować następujący przepływ wykonywania podczas uruchamiania programu:

  1. SaveChanges rozpoczyna wypychanie nowego bloga do bazy danych
  2. SaveChanges Zakończeniu
  3. Zapytanie dotyczące wszystkich blogów jest wysyłane do bazy danych
  4. Zwracanie zapytań i wyniki są zapisywane w konsoli
  5. Cytat dnia jest zapisywany w konsoli

Sync Output 

 

Asynchroniczna

Teraz, gdy mamy już uruchomiony program, możemy rozpocząć korzystanie z nowych słów kluczowych asynchronicznych i await. Wprowadziliśmy następujące zmiany w pliku Program.cs

  1. Wiersz 2: Instrukcja using dla System.Data.Entity przestrzeni nazw daje nam dostęp do metod rozszerzenia asynchronicznego EF.
  2. Wiersz 4. Instrukcja using dla System.Threading.Tasks przestrzeni nazw umożliwia korzystanie z Task typu .
  3. Wiersz 12 i 18: Przechwytujemy jako zadanie, które monitoruje postęp PerformSomeDatabaseOperations (wiersz 12), a następnie blokuje wykonywanie programu dla tego zadania do wykonania po zakończeniu wszystkich zadań dla programu (wiersz 18).
  4. Wiersz 25. Aktualizacja PerformSomeDatabaseOperations ma być oznaczona jako async i zwracana wartość Task.
  5. Wiersz 35: Teraz wywołujemy wersję asynchroniową SaveChanges i czekamy na jej ukończenie.
  6. Wiersz 42: Teraz wywołujemy wersję asynchronicznych ToList elementów i czekamy na wynik.

Aby uzyskać kompleksową listę dostępnych metod rozszerzeń w System.Data.Entity przestrzeni nazw, zapoznaj się z klasą QueryableExtensions . Musisz również dodać using System.Data.Entity instrukcje 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);
                    }
                }
            }
        }
    }

Teraz, gdy kod jest asynchroniczny, możemy obserwować inny przepływ wykonywania podczas uruchamiania programu:

  1. SaveChanges rozpoczyna wypychanie nowego bloga do bazy danych
    Po wysłaniu polecenia do bazy danych nie jest potrzebny więcej czasu obliczeniowego w bieżącym wątku zarządzanym. Metoda PerformDatabaseOperations zwraca (mimo że nie została zakończona wykonywanie) i przepływ programu w metodzie Main jest kontynuowany.
  2. Cytat dnia jest zapisywany w konsoli
    Ponieważ nie ma więcej pracy do wykonania w metodzie Main, zarządzany wątek jest blokowany w Wait wywołaniu do momentu zakończenia operacji bazy danych. Po jego zakończeniu pozostała część zostanie PerformDatabaseOperations wykonana.
  3. SaveChanges Zakończeniu
  4. Zapytanie dotyczące wszystkich blogów jest wysyłane do bazy danych
    Ponownie zarządzany wątek jest wolny do wykonywania innych czynności podczas przetwarzania zapytania w bazie danych. Ponieważ wszystkie inne wykonanie zostało ukończone, wątek po prostu zatrzyma się na wywołaniu Wait choć.
  5. Zwracanie zapytań i wyniki są zapisywane w konsoli

Async Output 

 

Na wynos

Teraz zobaczyliśmy, jak łatwo jest korzystać z metod asynchronicznych ef. Chociaż zalety asynchroniczne mogą nie być bardzo widoczne w prostej aplikacji konsolowej, te same strategie mogą być stosowane w sytuacjach, gdy długotrwałe lub związane z siecią działania mogą w przeciwnym razie blokować aplikację lub powodować dużą liczbę wątków w celu zwiększenia zużycia pamięci.