Eşzamansız sorgu ve kaydetme

Uyarı

YALNıZCA EF6'ya Doğru - Bu sayfada ele alınan özellikler, API'ler vb. Entity Framework 6'da sunulmuştur. Önceki bir sürümü kullanıyorsanız, bilgilerin bazıları veya tümü geçerli değildir.

EF6, .NET 4.5'te kullanıma sunulan zaman uyumsuz sorgu ve bekleme anahtar sözcüklerini kullanarak zaman uyumsuz sorgu ve kaydetme desteği sunar. Tüm uygulamalar zaman uyumsuzluktan yararlanamayabilir ancak uzun süre çalışan, ağ veya G/Ç'ye bağlı görevleri işlerken istemci yanıt hızını ve sunucu ölçeklenebilirliğini geliştirmek için kullanılabilir.

Gerçekten eşzamansız ne zaman kullanılır?

Bu kılavuzun amacı, zaman uyumsuz ve zaman uyumlu program yürütme arasındaki farkı gözlemlemesini kolaylaştıracak şekilde zaman uyumsuz kavramları tanıtmaktır. Bu izlenecek yol, zaman uyumsuz programlamanın avantaj sağladığı temel senaryoların hiçbirini göstermek için tasarlanmamıştır.

Zaman uyumsuz programlama, .NET kodu çalıştıran yönetilen iş parçacığını, işlem süresi gerektirmeyen bir işlemi beklerken diğer işleri yapmak için boşaltmaya odaklanır. Örneğin, veritabanı altyapısı bir sorguyu işlerken .NET kodu tarafından yapılacak bir şey yoktur.

İstemci uygulamalarında (WinForms, WPF vb.) zaman uyumsuz bir işlem gerçekleştirildiğinde kullanıcı arabiriminin yanıt vermesini sağlamak için geçerli iş parçacığı kullanılabilir. Sunucu uygulamalarında (ASP.NET vb.) iş parçacığı diğer gelen istekleri işlemek için kullanılabilir- bu, bellek kullanımını azaltabilir ve/veya sunucunun aktarım hızını artırabilir.

Çoğu uygulamada async kullanan bu durumu fark edilebilir bir avantaj sağlamaz ve hatta zararlı olabilir. Bağlanmadan önce belirli bir senaryonuzda asenkron işlemlerin etkisini ölçmek için testleri, profil çıkarmayı ve sağduyuyu kullanın.

Async hakkında daha fazla bilgi edinmek için daha fazla kaynak:

Modeli oluşturma

Modelimizi oluşturmak ve veritabanını oluşturmak için İlk Kod iş akışını kullanacağız ancak zaman uyumsuz işlevsellik, EF Designer ile oluşturulanlar da dahil olmak üzere tüm EF modelleriyle çalışır.

  • Konsol Uygulaması oluşturma ve AsyncDemo olarak çağırma
  • EntityFramework NuGet paketini ekleme
    • Çözüm Gezgini'nde AsyncDemo projesine sağ tıklayın
    • NuGet Paketlerini Yönet... öğesini seçin.
    • NuGet Paketlerini Yönet iletişim kutusunda Çevrimiçi sekmesini seçin ve EntityFramework paketini seçin
    • Yükle'ye tıklayın
  • Aşağıdaki uygulamayla Model.cs sınıfı ekleme
    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; }
        }
    }

 

Zaman uyumlu program oluşturma

Artık bir EF modelimiz olduğuna göre, veri erişimi gerçekleştirmek için bu modeli kullanan bazı kodlar yazalım.

  • Program.cs içeriğini aşağıdaki kodla değiştirin
    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);
                    }
                }
            }
        }
    }

Bu kod, veritabanına yeni bir PerformDatabaseOperations kaydeden yöntemini çağırır ve ardından veritabanından tüm Blogları alır ve konsola yazdırır. Bundan sonra, program konsola günün bir alıntısını yazar.

Kod zaman uyumlu olduğundan, programı çalıştırırken aşağıdaki yürütme akışını gözlemleyebiliriz:

  1. SaveChanges yeni Blogu veritabanına göndermeye başlar
  2. SaveChanges Tamamlar
  3. Tüm Bloglar için sorgu veritabanına gönderilir
  4. Sorgu döndürür ve sonuçlar Konsol'a yazılır
  5. Günün alıntısı Konsol'a yazılır

Çıktıyı Eşitle  

 

Eşzamanlı olmayan hale getirme

Artık programımız çalışır durumda olduğuna göre, yeni async ve await anahtar sözcüklerini kullanmaya başlayabiliriz. Program.cs'de aşağıdaki değişiklikleri yaptık

  1. 2. Satır: System.Data.Entity ad alanı için using deyimi, EF'nin zaman uyumsuz uzantı yöntemlerine erişim sağlar.
  2. 4. Satır: System.Threading.Tasks ad alanı için using ifadesi, Task tipini kullanmamızı sağlar.
  3. Satır 12 ve 18: PerformSomeDatabaseOperations unsuru, programın ilerleme durumunu izleyen bir görev olarak yakalanıyor (12. satır) ve ardından, program için tüm işler tamamlandığında, bu görev program yürütmesini engelliyor (18. satır).
  4. 25. Satır: PerformSomeDatabaseOperations öğesini async olarak işaretlenecek ve bir Task döndürecek şekilde güncelledik.
  5. 35: Şimdi SaveChanges asenkron sürümünü çağırıyor ve tamamlanmasını bekliyoruz.
  6. 42. Satır: Şimdi Async sürümünü ToList çağırıyoruz ve sonucu bekliyoruz.

System.Data.Entity ad alanındaki kullanılabilir uzantı yöntemlerinin kapsamlı bir listesi için QueryableExtensions sınıfına başvurun. Ayrıca using System.Data.Entity ifadesini using deyimlerinize eklemelisiniz.

    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);
                    }
                }
            }
        }
    }

Kod artık zaman uyumsuz olduğuna göre, programı çalıştırdığımızda farklı bir yürütme akışı gözlemleyebiliriz:

  1. SaveChanges yeni Blogu veritabanına göndermeye başlar
    Komut veritabanına gönderildikten sonra mevcut yönetilen iş parçacığı için daha fazla işlem süresi gerekmez. PerformDatabaseOperations yöntemi döndürür (yürütmeyi tamamlamamış olsa da) ve Main yöntemindeki program akışı devam eder.
  2. Günün alıntısı Konsol'a yazılır
    Main yönteminde yapılacak başka iş olmadığından, yönetilen iş parçacığı veritabanı işlemi tamamlanana kadar Wait çağrısında bloklanır. İşlem tamamlandıktan sonra geri kalan PerformDatabaseOperations'miz yürütülecek.
  3. SaveChanges Tamamlar
  4. Tüm Bloglar için sorgu veritabanına gönderilir
    Sorgu veritabanında işlenirken yönetilen iş parçacığının başka işler yapması da serbesttir. Diğer tüm yürütmeler tamamlandığından, iş parçacığı Bekleme çağrısında durur.
  5. Sorgu döndürür ve sonuçlar Konsol'a yazılır

Asenkron Çıkış  

 

Çıkarılacak Ders

ARTıK EF'in zaman uyumsuz yöntemlerini kullanmanın ne kadar kolay olduğunu gördük. Asenkron işlemlerin avantajları basit bir konsol uygulamasında çok belirgin olmasa da, uzun süre çalışan veya ağa bağlı işlemlerin uygulamayı engelleyebileceği ya da bellek ayak izini artırmak için çok sayıda iş parçacığına neden olabileceği durumlarda aynı stratejiler uygulanabilir.