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:
- Omówienie asynchronicznego/awaita Brandona Braya na platformie .NET 4.5
- Strony programowania asynchronicznego w bibliotece MSDN
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:
SaveChanges
rozpoczyna wypychanie nowego bloga do bazy danychSaveChanges
Zakończeniu- Zapytanie dotyczące wszystkich blogów jest wysyłane do bazy danych
- Zwracanie zapytań i wyniki są zapisywane w konsoli
- Cytat dnia jest zapisywany w konsoli
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
- Wiersz 2: Instrukcja using dla
System.Data.Entity
przestrzeni nazw daje nam dostęp do metod rozszerzenia asynchronicznego EF. - Wiersz 4. Instrukcja using dla
System.Threading.Tasks
przestrzeni nazw umożliwia korzystanie zTask
typu . - 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). - Wiersz 25. Aktualizacja
PerformSomeDatabaseOperations
ma być oznaczona jakoasync
i zwracana wartośćTask
. - Wiersz 35: Teraz wywołujemy wersję asynchroniową
SaveChanges
i czekamy na jej ukończenie. - 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:
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. MetodaPerformDatabaseOperations
zwraca (mimo że nie została zakończona wykonywanie) i przepływ programu w metodzie Main jest kontynuowany.- Cytat dnia jest zapisywany w konsoli
Ponieważ nie ma więcej pracy do wykonania w metodzie Main, zarządzany wątek jest blokowany wWait
wywołaniu do momentu zakończenia operacji bazy danych. Po jego zakończeniu pozostała część zostaniePerformDatabaseOperations
wykonana. SaveChanges
Zakończeniu- 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ć. - Zwracanie zapytań i wyniki są zapisywane w konsoli
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.