سلام به شما برنامه نویسان

امروز، بیایید در مورد چگونگی بهبود عملکرد در برنامه‌های NET از طریق روش AsNoTracking از Entity Framework صحبت کنیم.

درخواست های DB را می توان ردیابی کرد یا ردیابی نکرد. به طور پیش فرض، تمام پرس و جوهایی که اشیاء مدل را از DB برمی گرداند،از نوع ردیابی شده (Trackable) هستند.

هنگامی که Data context داده ها را از پایگاه داده بازیابی می کند، Entity Framework اشیاء بازیابی شده را در حافظه پنهان(Cache) قرار می دهد و تغییراتی را که برای آن اشیاء رخ می دهد نظارت می کند تا زمانی که از متد SaveChanges() یا SaveChangesAsync() استفاده کند، که هر تغییری را در پایگاه داده ثبت نماید. اما ما همیشه نیازی به پیگیری تغییرات نداریم. به عنوان مثال، ما فقط باید داده ها را برای مشاهده نمایش دهیم.

برای جلوگیری از کش شدن داده ها، از متد AsNoTracking() استفاده می شود. هنگامی که AsNoTracking() اعمال می شود، داده های بازگردانده شده از درخواست ذخیره نمی شوند، یعنی درخواست ردیابی نمی شود. این بدان معنی است که Entity Framework هیچ پردازش اضافی را انجام نمی دهد و فضای اضافی را برای ذخیره اشیاء بازیابی شده از پایگاه داده، اختصاص نمی دهد. و بنابراین، چنین پرس و جوهایی  سریعتر هستند.

حالا بریم سر تمرین :)

فرض کنید مدل ها و Data Context زیر را داریم:

using Microsoft.EntityFrameworkCore;

namespace AsNoTrackinsExample
{
    public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
    }

    public class AppDbContext : DbContext
    {
        public DbSet<User> Users { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer("yoursConnectionString");
        }
    }
}

و من 6828 ردیف را برای جدول کاربران در پایگاه داده قرار داده ام.

مرحله بعدی - دریافت داده از DB بدون AsNoTracking و با AsNoTracking و مقایسه عملکرد آنها میباشد. برای مقایسه از بنچمارک استفاده می کنم.

using System.Collections.Generic;
using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using Microsoft.EntityFrameworkCore;

namespace AsNoTrackinsExample
{
    class Program
    {
        static void Main(string[] args)
        {
            var summary = BenchmarkRunner.Run<MemoryBenchmarkerDemo>();
        }
    }

    [MemoryDiagnoser]
    public class MemoryBenchmarkerDemo
    {
        [Benchmark]
        public List<User> GetUsers()
        {
            using (AppDbContext db = new AppDbContext())
            {
                return db.Users.ToList();
            }
        }

        [Benchmark]
        public List<User> GetUsersWithNoTracking()
        {
            using (AppDbContext db = new AppDbContext())
            {
                return db.Users.AsNoTracking().ToList();
            }
        }
    }
}

خروجی برنامه

وای! ما می توانیم برتری را هم در سرعت اجرا و هم در استفاده از حافظه مشاهده کنیم. تفاوت ها در مقادیر زیادی از داده ها بیشتر بوده و قابل توجه خواهد بود.

اما به یاد داشته باشید که ما نمی‌توانیم هیچ مورد یا مجموعه‌ای را که با AsNoTracking دریافت کرده‌ایم به‌روزرسانی کنیم، زیرا Entity Framework این اشیاء را در حافظه پنهان ذخیره نمی‌کند.

using System.Linq;
using Microsoft.EntityFrameworkCore;

namespace AsNoTrackinsExample
{
    class Program
    {
        static void Main(string[] args)
        {
            using (AppDbContext db = new AppDbContext())
            {
                var user = db.Users.AsNoTracking().FirstOrDefault();
                user.Age = 22;
                db.SaveChanges(); // Age will not be updated 
            }
        }
    }
}

علاوه بر استفاده از روش AsNoTracking، می توانید ردیابی را به طور کلی برای Data context غیرفعال کنید.

برای انجام این کار، مقدار false را برای ویژگی db.ChangeTracker.AutoDetectChangesEnabled تنظیم کنید:

using Microsoft.EntityFrameworkCore;

namespace AsNoTrackinsExample
{
    class Program
    {
        static void Main(string[] args)
        {
            using (AppDbContext db = new AppDbContext())
            {
                db.ChangeTracker.AutoDetectChangesEnabled = false;
                ...
            }
        }
    }
}

به طور کلی از طریق ویژگی ChangeTracker می توانیم ردیابی یک شی را مدیریت کنیم و اطلاعات مختلفی را دریافت کنیم. به عنوان مثال، ما می توانیم بفهمیم که در حال حاضر چند شی در حال ردیابی هستند:

using System.Linq;

namespace AsNoTrackinsExample
{
    class Program
    {
        static void Main(string[] args)
        {
            using (AppDbContext db = new AppDbContext())
            {
                var users = db.Users.ToList();

                int count = db.ChangeTracker.Entries().Count();
            }
        }
    }
}

چه زمانی باید از AsNoTracking استفاده کنید؟ اگر فقط نیاز به نمایش داده ها برای نمایش بدون نیاز به تفییرات و به روزرسانی اطلاعات دارید، در این صورت است که می توانیم از AsNoTracking استفاده کنیم.

از کدنویسی لذت ببرید 🤓

 

منبع: blog.devgenius.io