کدهای کامل این مثال را در ذیل ملاحظه میکنید:
using System; using System.Data.Entity; using System.Data.Entity.Migrations; using System.Diagnostics; using System.Linq; namespace EFGeneral { public class User { public int Id { get; set; } public string Name { get; set; } } public class MyContext : DbContext { public DbSet<User> Users { get; set; } } public class Configuration : DbMigrationsConfiguration<MyContext> { public Configuration() { AutomaticMigrationsEnabled = true; AutomaticMigrationDataLossAllowed = true; } protected override void Seed(MyContext context) { for (int i = 0; i < 21000; i++) { context.Users.Add(new User { Name = "name " + i }); if (i % 1000 == 0) context.SaveChanges(); } base.Seed(context); } } public class PerformanceHelper { public static string RunActionMeasurePerformance(Action action) { GC.Collect(); long initMemUsage = Process.GetCurrentProcess().WorkingSet64; var stopwatch = new Stopwatch(); stopwatch.Start(); action(); stopwatch.Stop(); var currentMemUsage = Process.GetCurrentProcess().WorkingSet64; var memUsage = currentMemUsage - initMemUsage; if (memUsage < 0) memUsage = 0; return string.Format("Elapsed time: {0}, Memory Usage: {1:N2} KB", stopwatch.Elapsed, memUsage / 1024); } } public static class Test { public static void RunTests() { Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, Configuration>()); StartDb(); for (int i = 0; i < 3; i++) { Console.WriteLine("\nRun {0}", i + 1); var memUsage = PerformanceHelper.RunActionMeasurePerformance(() => LoadWithTracking()); Console.WriteLine("LoadWithTracking:\n{0}", memUsage); memUsage = PerformanceHelper.RunActionMeasurePerformance(() => LoadWithoutTracking()); Console.WriteLine("LoadWithoutTracking:\n{0}", memUsage); } } private static void StartDb() { using (var ctx = new MyContext()) { var user = ctx.Users.Find(1); if (user != null) { // keep the object in memory } } } private static void LoadWithTracking() { using (var ctx = new MyContext()) { var list = ctx.Users.ToList(); if (list.Any()) { // keep the list in memory } } } private static void LoadWithoutTracking() { using (var ctx = new MyContext()) { var list = ctx.Users.AsNoTracking().ToList(); if (list.Any()) { // keep the list in memory } } } } }
توضیحات:
مدل برنامه یک کلاس ساده کاربر است به همراه id و نام او.
سپس این کلاس توسط Context برنامه در معرض دید EF Code first قرار میگیرد.
در کلاس Configuration تعدادی رکورد را در ابتدای کار برنامه در بانک اطلاعاتی ثبت خواهیم کرد. قصد داریم میزان مصرف حافظه بارگذاری این اطلاعات را بررسی کنیم.
کلاس PerformanceHelper معرفی شده، دو کار اندازه گیری میزان مصرف حافظه برنامه در طی اجرای یک فرمان خاص و همچنین مدت زمان سپری شدن آنرا اندازهگیری میکند.
در کلاس Test فوق چندین متد به شرح زیر وجود دارند:
متد StartDb سبب میشود تا تنظیمات ابتدایی برنامه به بانک اطلاعاتی اعمال شوند. تا زمانیکه کوئری خاصی به بانک اطلاعاتی ارسال نگردد، EF Code first بانک اطلاعاتی را آغاز نخواهد کرد.
در متد LoadWithTracking اطلاعات تمام رکوردها به صورت متداولی بارگذاری شده است.
در متد LoadWithoutTracking نحوه استفاده از متد الحاقی AsNoTracking را مشاهده میکنید. در این متد سطح اول کش به این ترتیب خاموش میشود.
و متد RunTests، این متدها را در سه بار متوالی اجرا کرده و نتیجه عملیات را نمایش خواهد داد.
برای نمونه این نتیجه در اینجا حاصل شده است:
همانطور که ملاحظه کنید، بین این دو حالت، تفاوت بسیار قابل ملاحظه است؛ چه از لحاظ مصرف حافظه و چه از لحاظ سرعت.
نتیجه گیری:
اگر قصد ندارید بر روی اطلاعات دریافتی از بانک اطلاعاتی تغییرات خاصی را انجام دهید و فقط قرار است از آنها به صورت فقط خواندنی گزارشگیری شود، بهتر است سطح اول کش را به کمک متد الحاقی AsNoTracking خاموش کنید.