در جهت تکمیل بحث بارگذاری اطلاعات وابسته: اضافه شدن Lazy Loading به نگارش 2.1
برخلاف نگارشهای پیشین EF، اینبار Lazy loading به صورت پیشفرض فعال نیست که در بسیاری از موارد یک مزیت مهم، در جهت بهبود کارآیی برنامه به حساب میآید؛ چون پیشتر مدام میبایستی توسط ابزارهای profiler، برنامه را بررسی میکردیم تا از وجود مشکلی به نام select n+1 مطلع میشدیم (lazy loading اشتباه، در جائی که نیازی به آن نبوده و رفت و برگشت بیش از اندازهای را به بانک اطلاعاتی سبب شدهاست).
برای فعالسازی lazy loading در EF Core 2.1 (اگر واقعا به آن نیاز دارید البته) دو روش وجود دارد:
الف) فعالسازی Lazy loading توسط Proxyها
در این حالت ابتدا نیاز است بستهی نیوگت
Microsoft.EntityFrameworkCore.Proxies را نصب کنید. سپس در متد OnConfiguring مربوط به Context برنامه، متد UseLazyLoadingProxies را فراخوانی نمائید:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseLazyLoadingProxies()
.UseSqlServer(myConnectionString);
و یا اینکار در فایل آغازین برنامه نیز میسر است:
.AddDbContext<BloggingContext>(
b => b.UseLazyLoadingProxies()
.UseSqlServer(myConnectionString));
اکنون EF Core 2.1 خواص راهبری (navigation properties) را که قابل بازنویسی باشند (همان مباحث AOP و تشکیل پروکسیها)، lazy load میکند.
این خواص نیز حتما باید به صورت virtual معرفی شوند تا قابلیت بازنویسی را داشته باشند؛ مانند:
public class Blog
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public virtual Blog Blog { get; set; }
}
در این مثال با فعال بودن lazy loading، به محض لمس خاصیت Blog، اطلاعات مرتبط با آن از بانک اطلاعاتی واکشی خواهند شد و نه پیش از آن مانند eager loading که تمام اطلاعات وابستهی به یک موجودیت را نیز واکشی میکند.
هرچند این قابلیت بارگذاری اطلاعات وابسته در آینده، جذاب به نظر میرسد اما در عمل در حین رندر یک گرید و یا بکارگیری حلقهها، چون سبب رفت و برگشت بیش از اندازهای به بانک اطلاعاتی خواهد شد، باید با دقت مورد استفاده قرار گیرد و اساسا استفادهی از آن در برنامههای وب توصیه نمیشود (با بررسیهای پروژههای بسیاری مشخص شدهاست که این قابلیت ضررش بیشتر از نفعش است).
ب) فعالسازی Lazy loading بدون استفاده از Proxyها
در این حالت نیازی به نصب بستهی AOP جدید تشکیل پروکسیها نیست. در اینجا در کلاس موجودیت خود باید سرویس ILazyLoader را تزریق کنید:
public class Blog
{
private ICollection<Post> _posts;
public Blog()
{
}
private Blog(ILazyLoader lazyLoader)
{
LazyLoader = lazyLoader;
}
private ILazyLoader LazyLoader { get; set; }
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Post> Posts
{
get => LazyLoader?.Load(this, ref _posts);
set => _posts = value;
}
}
public class Post
{
private Blog _blog;
public Post()
{
}
private Post(ILazyLoader lazyLoader)
{
LazyLoader = lazyLoader;
}
private ILazyLoader LazyLoader { get; set; }
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public Blog Blog
{
get => LazyLoader?.Load(this, ref _blog);
set => _blog = value;
}
}
در این روش نیازی به virtual معرفی کردن خواص راهبری نیست. اما در این حالت به علت استفادهی از سرویس ILazyLoader، نیاز خواهید داشت تا بستهی نیوگت
Microsoft.EntityFrameworkCore.Abstractions را نیز نصب کنید.