بارگذاری Entity های مرتبط در Entity Framework

پنجشنبه 20 آبان 1395

EF از سه روش برای بارگذاری داده های مرتبط پشتیبانی میکند . eager loadin و lazy loading و explicit loading ... در این مقاله با استفاده از Code First به بررسی این روش ها خواهیم پرداخت .

بارگذاری Entity های مرتبط در Entity Framework

Eagerly Loading :
Eagerly Loading  یک پردازش است که با آن یک کوئری برای یک نوع Entity ، Entity های مرتبط را نیز به عنوان قسمتی از کوئری بارگذاری میکند . Eagerly Loading بوسیله استفاده از متد Include حاصل می‌شود . برای مثال ، کوئری زیر blogها و همه پست های مرتبط با آن blog را بارگذاری میکند .

using (var context = new BloggingContext()) 
{ 
    // Load all blogs and related posts 
    var blogs1 = context.Blogs 
                          .Include(b => b.Posts) 
                          .ToList(); 
 
    // Load one blogs and its related posts 
    var blog1 = context.Blogs 
                        .Where(b => b.Name == "ADO.NET Blog") 
                        .Include(b => b.Posts) 
                        .FirstOrDefault(); 
 
    // Load all blogs and related posts  
    // using a string to specify the relationship 
    var blogs2 = context.Blogs 
                          .Include("Posts") 
                          .ToList(); 
 
    // Load one blog and its related posts  
    // using a string to specify the relationship 
    var blog2 = context.Blogs 
                        .Where(b => b.Name == "ADO.NET Blog") 
                        .Include("Posts") 
                        .FirstOrDefault(); 
}

توجه داشته باشید که Include یک extension method است که در فضانام System.Data.Entity وجود دارد ، پس مطمئن شوید که از این فضانام استفاده کرده باشید . 


بارگذاری Eagerly چند سطحی :

همچنین امکان بارگذاری Eagerly چند سطحی entity های مرتبط نیز وجود دارد . به مثال زیر توجه کنید :

using (var context = new BloggingContext()) 
{ 
    // Load all blogs, all related posts, and all related comments 
    var blogs1 = context.Blogs 
                       .Include(b => b.Posts.Select(p => p.Comments)) 
                       .ToList(); 
 
    // Load all users their related profiles, and related avatar 
    var users1 = context.Users 
                        .Include(u => u.Profile.Avatar) 
                        .ToList(); 
 
    // Load all blogs, all related posts, and all related comments  
    // using a string to specify the relationships 
    var blogs2 = context.Blogs 
                       .Include("Posts.Comments") 
                       .ToList(); 
 
    // Load all users their related profiles, and related avatar  
    // using a string to specify the relationships 
    var users2 = context.Users 
                        .Include("Profile.Avatar") 
                        .ToList(); 
}

توجه داشته باشید که در حال حاضر امکان فیلتر گذاشتن روی entity های مرتبط بارگذاری شده وجود ندارد . Include همیشه در Entityهای مرتبط می‌آیند . 

Lazy Loading :

Lazy Loading پردازشی است که در طی آن یک entity با لیستی از entity ها ،  اولین باری که یک Property به این entity یا entityها ارجاع داده شوند ،  بصورت خودکار از پایگاه داده بارگذاری می‌شوند . زمانی که از نوع POCO در entity استفاده می‌کنیم ، lazy loading بوسیله ایجاد یک نمونه از نوع مشتق شده Proxy حاصل میشود و سپس برای اضافه کردن بارگذاری مشخصه های مجازی را Override می‌کند . برای مثال ، زمانی که از کلاس Blog entity زیر استفاده میکنیم ، پست های مرتبط نیز در دفعه ی اولی که مشخصه ی  Post navigation پردازش میشود ،  بارگذاری می‌شوند .

public class Blog 
{  
    public int BlogId { get; set; }  
    public string Name { get; set; }  
    public string Url { get; set; }  
    public string Tags { get; set; }  
 
    public virtual ICollection<Post> Posts { get; set; }  
}


غیر فعال کردن Lazy Load برای Serialization :
Lazy Load  و Serialization خیلی خوب با هم ترکیب نمی‌شوند ، و اگر مراقب نباشید ، بخاطر فعال بودن
Lazy Loading کوئری گرفتن از کل پایگاه داده به پایان میرسد . اکثر serializers ها با انجام پردازش بر روی یک نمونه از یک نوع ، کار میکنند . مشخصه ها Lazy Loading را راه می‌اندازند ، بنابراین entity های بیشتری serialized می‌شوند . 
این تمرین خوبی برای غیر فعال کردن lazy loading قبل از serialization روی یک entity است . در بخش زیر با چگونگی انجام آن آشنا خواهید شد :

غیر فعال کردن lazy loading برای یک navigation propery مشخص :

با non-virtual قرار دادن post property میتوان lazy loading یک post collection را غیر فعال کرد :

public class Blog 
{  
    public int BlogId { get; set; }  
    public string Name { get; set; }  
    public string Url { get; set; }  
    public string Tags { get; set; }  
 
    public ICollection<Post> Posts { get; set; }  
}

غیر فعال کردن lazy loading  برای تمام entity ها :

lazy loading میتواند برای تمام entity ها ، با قرار دادن یک flag برای Configuration property در context ، غیرفعال شود . برای مثال :

public class BloggingContext : DbContext 
{ 
    public BloggingContext() 
    { 
        this.Configuration.LazyLoadingEnabled = false; 
    } 
}


Explicitly Loading :
حتی زمانی که lazy loading غیر فعال است ، هنوز امکان استفاده از lazy load برای entity های مرتبط وجود دارد ، اما این باید بوسیله فراخوانی explicit loading انجام شود . برای انجام این کار از متد load برای ورود entityهای مرتبط استفاده میکنیم . برای مثال :  

using (var context = new BloggingContext()) 
{ 
    var post = context.Posts.Find(2); 
 
    // Load the blog related to a given post 
    context.Entry(post).Reference(p => p.Blog).Load(); 
 
    // Load the blog related to a given post using a string  
    context.Entry(post).Reference("Blog").Load(); 
 
    var blog = context.Blogs.Find(1); 
 
    // Load the posts related to a given blog 
    context.Entry(blog).Collection(p => p.Posts).Load(); 
 
    // Load the posts related to a given blog  
    // using a string to specify the relationship 
    context.Entry(blog).Collection("Posts").Load(); 
}

توجه داشته باشید که Reference method بهتر است زمانی استفاده شود که یک entity ، یک navigation property به یک single entity داشته باشد . از طرف دیگر ، Collection method بهتر است زمانی استفاده شود که یک entity ، یک navigation property به یک مجموعه ای از entityها داشته باشد


بکار بردن filterها در زمان استفاده از explicitly loading برای entityهای مرتبط : 

Query method پردازشی را برای کوئری های اساسی فراهم می‌آورد که Entity Framework در زمان بارگذاری entityهای مرتبط از آنها استفاده میکند . سپس میتوانید از LINQ برای اعمال Filterها به کوئری ها ، قبل از اجرای آنها ، استفاده کنید . این کار را میتوانید با فراخوانی extension methodهایی از LINQ همانند ToList , Load و ... انجام دهید . 
Query method میتواند هم با refrence و هم با collection navigation propertiyها مورد استفاده قرار گیرد . اما در صورتی که قسمتی از مجموعه را بارگذاری کند ، بیشتر برای مجموعه مفید است . برای  مثال :

using (var context = new BloggingContext()) 
{ 
    var blog = context.Blogs.Find(1); 
 
    // Load the posts with the 'entity-framework' tag related to a given blog 
    context.Entry(blog) 
        .Collection(b => b.Posts) 
        .Query() 
        .Where(p => p.Tags.Contains("entity-framework") 
        .Load(); 
 
    // Load the posts with the 'entity-framework' tag related to a given blog  
    // using a string to specify the relationship  
    context.Entry(blog) 
        .Collection("Posts") 
        .Query() 
        .Where(p => p.Tags.Contains("entity-framework") 
        .Load(); 
}

زمانی که از متد Query استفاده میکنید ، بهترین کار این است که lazy load را برای navigation propery غیر فعال کنید . چون در غیر این صورت تمام مجموعه توسط مکانیزم lazy load بارگذاری میشود .

توجه داشته باشید که relationship میتواند بجای lambda expresion تحت عنوان یک string مشخص شود ، IQueryable بازگشتی زمانی که یک رشته مورد استفاده قرار میگرد ،  generic نمیباشد ، بنابراین متد cast قبل از هر چیزی نیاز است .

استفاده از Query برای شمردن related entityها بدون بارگذاری آنها :


گاهی اوقات نیاز است که بدون هزینه برای بارگذاری تمام entity ها ، از تعداد رابطه های entity با entity های دیگر در پایگاه داده مطلع شویم .  متد Query با متد LINQ count برای انجام این کار میتواند مورد استفاده قرار بگیرد ، برای مثال : 

using (var context = new BloggingContext()) 
{ 
    var blog = context.Blogs.Find(1); 
 
    // Count how many posts the blog has  
    var postCount = context.Entry(blog) 
                          .Collection(b => b.Posts) 
                          .Query() 
                          .Count(); 
}

آموزش سی شارپ

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

نویسنده 3355 مقاله در برنامه نویسان
  • C#.net
  • 5k بازدید
  • 3 تشکر

کاربرانی که از نویسنده این مقاله تشکر کرده اند

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید