Поделиться через


Асинхронный запрос и сохранение

Примечание.

Только в EF6 и более поздних версиях. Функции, API и другие возможности, описанные на этой странице, появились в Entity Framework 6. При использовании более ранней версии могут быть неприменимы некоторые или все сведения.

EF6 представила поддержку асинхронного запроса и сохранения с помощью асинхронных и ожидающих ключевое слово, появившихся в .NET 4.5. Хотя не все приложения могут воспользоваться асинхронностью, ее можно использовать для повышения скорости реагирования клиентов и масштабируемости сервера при обработке длительных задач, сетевых или сетевых операций ввода-вывода.

Когда действительно использовать асинхронную

Цель этого пошагового руководства — ввести асинхронные понятия таким образом, чтобы было легко наблюдать разницу между асинхронным и синхронным выполнением программы. Это пошаговое руководство не предназначено для иллюстрации любого из ключевых сценариев, в которых асинхронное программирование обеспечивает преимущества.

Асинхронное программирование в основном сосредоточено на освобождении текущего управляемого потока (поток под управлением кода .NET) для выполнения другой работы во время ожидания операции, которая не требует времени вычислений из управляемого потока. Например, в то время как ядро СУБД обрабатывает запрос, не требуется ничего делать с помощью кода .NET.

В клиентских приложениях (WinForms, WPF и т. д.) текущий поток можно использовать для реагирования пользовательского интерфейса при выполнении асинхронной операции. В серверных приложениях (ASP.NET и т. д.) поток можно использовать для обработки других входящих запросов. Это может снизить использование памяти и /или увеличить пропускную способность сервера.

В большинстве приложений, использующих асинхронный код, не будет заметных преимуществ и даже может быть вредным. Используйте тесты, профилирование и здравый смысл, чтобы оценить влияние асинхронного асинхронного сценария перед фиксацией в нем.

Ниже приведены дополнительные ресурсы для получения сведений об асинхронном коде:

Создание модели

Мы будем использовать рабочий процесс Code First для создания модели и создания базы данных, однако асинхронная функциональность будет работать со всеми моделями EF, включая созданные с помощью конструктора EF.

  • Создание консольного приложения и вызов asyncDemo
  • Добавление пакета NuGet EntityFramework
    • В Обозреватель решений щелкните правой кнопкой мыши проект AsyncDemo
    • Выберите " Управление пакетами NuGet...
    • В диалоговом окне "Управление пакетами NuGet" выберите вкладку "Интернет" и выберите пакет EntityFramework
    • Щелкните Установить.
  • Добавление класса Model.cs со следующей реализацией
    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; }
        }
    }

 

Создание синхронной программы

Теперь, когда у нас есть модель EF, давайте напишите код, который использует его для выполнения доступа к данным.

  • Замените содержимое Program.cs следующим кодом.
    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);
                    }
                }
            }
        }
    }

Этот код вызывает PerformDatabaseOperations метод, который сохраняет новый блог в базе данных, а затем извлекает все блоги из базы данных и выводит их в консоль. После этого программа записывает цитату дня в консоль.

Так как код синхронен, при запуске программы можно наблюдать следующий поток выполнения:

  1. SaveChanges начинает отправлять новый блог в базу данных
  2. SaveChanges Завершает
  3. Запрос ко всем блогам отправляется в базу данных
  4. Возвращаемые запросы и результаты записываются в консоль
  5. Цитата дня записывается в консоль

Sync Output 

 

Создание асинхронного

Теперь, когда у нас есть программа, мы можем начать использовать новые асинхронные и ожидающие ключевое слово. Мы внесли следующие изменения в Program.cs

  1. Строка 2. Оператор using для System.Data.Entity пространства имен предоставляет нам доступ к методам расширения асинхронного расширения EF.
  2. Строка 4. Оператор using для System.Threading.Tasks пространства имен позволяет использовать Task тип.
  3. Строка 12 и 18. Мы захватываем как задачу, отслеживающую ход выполнения PerformSomeDatabaseOperations (строка 12), а затем блокируем выполнение программы для выполнения этой задачи после завершения всей работы программы (строка 18).
  4. Строка 25. Мы обновили, PerformSomeDatabaseOperations чтобы они были помечены как async и возвращаются Task.
  5. Строка 35. Теперь мы вызываем асинхронную SaveChanges версию и ожидаем его завершения.
  6. Строка 42. Теперь мы вызываем асинхронную ToList версию и ожидаем результата.

Полный список доступных методов расширения в System.Data.Entity пространстве имен см. в QueryableExtensions классе. Вам также потребуется добавить using System.Data.Entity в инструкции 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);
                    }
                }
            }
        }
    }

Теперь, когда код является асинхронным, мы можем наблюдать другой поток выполнения при запуске программы:

  1. SaveChanges начинает отправлять новый блог в базу данных
    После отправки команды в базу данных не требуется больше времени вычислений в текущем управляемом потоке. Метод PerformDatabaseOperations возвращает (даже если он не завершил выполнение) и поток программы в методе Main продолжается.
  2. Цитата дня записывается в консоль
    Так как в методе Main больше нет никаких действий, управляемый поток блокируется при вызове Wait до завершения операции базы данных. Завершив его, оставшаяся часть будет PerformDatabaseOperations выполнена.
  3. SaveChanges Завершает
  4. Запрос ко всем блогам отправляется в базу данных
    Опять же, управляемый поток может выполнять другие действия во время обработки запроса в базе данных. Так как все остальные выполнение завершено, поток просто остановится на вызове Wait, хотя.
  5. Возвращаемые запросы и результаты записываются в консоль

Async Output 

 

Вынос

Теперь мы узнали, насколько легко использовать асинхронные методы EF. Хотя преимущества асинхронного асинхронного приложения могут быть не очень очевидными в простом консольном приложении, эти же стратегии могут применяться в ситуациях, когда длительные или сетевые действия могут в противном случае заблокировать приложение или вызвать большое количество потоков, чтобы увеличить объем памяти.