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

Примечание

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

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

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

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

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

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

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

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

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

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

  • Создание консольного приложения и вызов его асинкдемо
  • добавление пакета NuGet EntityFramework
    • В обозреватель решений щелкните правой кнопкой мыши проект асинкдемо
    • выберите управление пакетами 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 метод, который сохраняет новый PerformDatabaseOperations в базе данных, а затем извлекает все блоги из базы данных и выводит их на консоль. После этого программа записывает в консолькавычки дня.

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

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

Sync Output 

 

Асинхронное выполнение

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

  1. Строка 2. оператор using для System.Data.Entity пространства имен предоставляет нам доступ к методам расширения EF Async.
  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.EntityQueryableExtensions класса. Также необходимо добавить в операторы 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 начинает передачу нового SaveChanges в базу данных
    После отправки команды в базу данных больше не требуется времени вычислений в текущем управляемом потоке. PerformDatabaseOperationsМетод возвращает значение (несмотря на то, что он не завершил выполнение) и выполнение программы в методе Main продолжится.
  2. Цитата дня записывается в консоль
    Поскольку больше нет работы в методе Main, управляемый поток блокируется в Wait вызове до тех пор, пока не завершится операция базы данных. После завершения работы будет выполнен остальная часть нашего PerformDatabaseOperations .
  3. SaveChanges завершения
  4. Запрос всех блогов отправлен в базу данных
    Опять же, управляемый поток свободен для выполнения других задач, пока запрос обрабатывается в базе данных. Так как все остальные выполнения завершены, поток просто останавливается на вызове Wait.
  5. Возвращаемые запросы и результаты записываются в консоль

Async Output 

 

Мысль

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