0Pricing
C# Academy · درس

التحميل المبكر والكسول والصريح

تحكّموا في وقت تحميل البيانات المرتبطة باستخدام Include وThenInclude ووكلاء التحميل الكسول واستدعاءات Load الصريحة.

التحميل المبكر والكسول والصريح درس مجاني في C# Academy على CoddyKit. هذا هو الدرس 1 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في C# Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة C# Academy 4 دروس في المجموع.

استراتيجيات التحميل الثلاث

توفّر EF Core ثلاث استراتيجيات لتحميل البيانات المرتبطة: التحميل المبكر (تحميلها مع الاستعلام)، والتحميل الكسول (تحميلها عند الوصول إليها)، والتحميل الصريح (تحميلها عند الطلب). ويساعد اختيار الاستراتيجية المناسبة على تجنّب مشكلة N+1 وعمليات الذهاب والإياب غير الضرورية إلى قاعدة البيانات.

التحميل المبكر باستخدام Include

يستخدم التحميل المبكر Include() لإجراء JOIN للبيانات المرتبطة ضمن استعلام SQL نفسه. وتُعد هذه الاستراتيجية الأكثر قابلية للتنبؤ، كما تتجنّب مشكلات N+1.

// Single query with JOIN
var blogs = await _db.Blogs
    .Include(b => b.Posts)
    .Where(b => b.IsActive)
    .ToListAsync();

// SQL: SELECT * FROM Blogs LEFT JOIN Posts ON ...

استخدام ThenInclude للعلاقات المتداخلة

يتيح ThenInclude التعمّق أكثر في مخطط التنقّل. ويمكنك تحميل مستويات متعددة ضمن استعلام واحد.

var orders = await _db.Orders
    .Include(o => o.Customer)
    .Include(o => o.Lines)
        .ThenInclude(l => l.Product)
            .ThenInclude(p => p.Category)
    .Where(o => o.Status == OrderStatus.Pending)
    .ToListAsync();

Include مع التصفية

تدعم EF Core 5 والإصدارات الأحدث تصفية البيانات المرتبطة داخل Include. ويتيح لك ذلك تحميل مجموعة فرعية من الكيانات الأبناء دون إجراء استعلام منفصل.

// Load only published posts for each blog
var blogs = await _db.Blogs
    .Include(b => b.Posts.Where(p => p.IsPublished)
                         .OrderByDescending(p => p.PublishedAt)
                         .Take(5))
    .ToListAsync();

إعداد التحميل الكسول

يحمّل التحميل الكسول خصائص التنقّل تلقائيًا عند الوصول إليها للمرة الأولى. فعّله بتثبيت الحزمة Microsoft.EntityFrameworkCore.Proxies واستدعاء UseLazyLoadingProxies().

// 1. Install package: dotnet add package Microsoft.EntityFrameworkCore.Proxies
// 2. Enable in DbContext setup:
builder.Services.AddDbContext<AppDbContext>(opt =>
    opt.UseSqlite(connStr)
       .UseLazyLoadingProxies());

// 3. Mark navigation properties as virtual:
public class Blog
{
    public int Id { get; set; }
    public virtual ICollection<Post> Posts { get; set; } = new List<Post>();
}

التحميل الكسول عمليًا (وفخ N+1)

يُعد التحميل الكسول مريحًا، لكنه خطير داخل الحلقات — إذ يؤدي كل وصول إلى تشغيل استعلام SQL جديد، مما يسبب مشكلة N+1. احرص دائمًا على تفضيل التحميل المبكر في سيناريوهات القوائم.

var blogs = await _db.Blogs.ToListAsync(); // 1 query

foreach (var blog in blogs)
{
    // BAD: each access fires a new query!
    var count = blog.Posts.Count; // N queries
    Console.WriteLine(count);
}

// FIX: Use eager loading
var blogs2 = await _db.Blogs.Include(b => b.Posts).ToListAsync();

التحميل الصريح

يتيح لك التحميل الصريح تحميل خاصية تنقّل عند الطلب باستخدام Entry().Collection().LoadAsync() أو Entry().Reference().LoadAsync(). ويكون مفيدًا عندما تحتاج إلى البيانات المرتبطة بشكل مشروط.

var blog = await _db.Blogs.FindAsync(1); // no posts loaded

// Load posts only when needed
if (needsPosts)
{
    await _db.Entry(blog!)
             .Collection(b => b.Posts)
             .LoadAsync();
}

// Load single reference
var post = await _db.Posts.FindAsync(99);
await _db.Entry(post!)
         .Reference(p => p.Blog)
         .LoadAsync();

التحميل الصريح مع عامل تصفية للاستعلام

يمكنك تصفية التحميل الصريح باستخدام .Query() قبل استدعاء LoadAsync()، مما يقلل كمية البيانات التي يتم إرجاعها.

var blog = await _db.Blogs.FindAsync(1);

// Only load posts published this year
await _db.Entry(blog!)
         .Collection(b => b.Posts)
         .Query()
         .Where(p => p.PublishedAt.Year == DateTime.UtcNow.Year)
         .LoadAsync();

Console.WriteLine(blog!.Posts.Count);

الاستعلامات المنقسمة مع عمليات Include الكبيرة

يؤدي تحميل مجموعات متعددة في استعلام واحد إلى تضخم كارتيزي، حيث تتضاعف الصفوف. استخدم AsSplitQuery() لإصدار استعلامات منفصلة لكل مجموعة، ثم ربط النتائج في الذاكرة.

var orders = await _db.Orders
    .Include(o => o.Lines)
    .Include(o => o.Shipments)
    .AsSplitQuery()  // 3 separate SELECTs instead of one giant JOIN
    .ToListAsync();

// Or configure globally:
opt.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery);

الإسقاط لتجنب جلب بيانات زائدة

بدلًا من تحميل الكيانات الكاملة مع جميع علاقاتها، أسقط البيانات إلى DTO باستخدام Select. يتيح لك ذلك الحصول على البيانات التي تحتاج إليها بالضبط في استعلام واحد محسّن.

var summaries = await _db.Blogs
    .Select(b => new BlogSummaryDto
    {
        Name      = b.Name,
        PostCount = b.Posts.Count(p => p.IsPublished),
        LatestPost = b.Posts
            .Where(p => p.IsPublished)
            .OrderByDescending(p => p.PublishedAt)
            .Select(p => p.Title)
            .FirstOrDefault()
    })
    .ToListAsync();
// No Include needed - translated to subqueries

عمليًا: اختيار الاستراتيجية المناسبة

استخدم دليل اتخاذ القرار هذا عمليًا:

  • التحميل المبكر + Include: عندما تحتاج دائمًا إلى البيانات المرتبطة، مثل صفحات القوائم
  • الإسقاط: للواجهات للقراءة فقط واستجابات API — وهو الخيار الأكثر كفاءة
  • التحميل الصريح: للتحميل المشروط بناءً على منطق التطبيق
  • التحميل الكسول: تجنّبه في تطبيقات الويب؛ واستخدمه فقط في تطبيقات سطح المكتب أو البرمجة النصية مع مجموعات بيانات صغيرة

تحقق سريع

ما مشكلة N+1 في سياق التحميل الكسول؟

مراجعة: استراتيجيات التحميل

أهم النقاط:

  • التحميل المبكر (Include): يحمّل البيانات في استعلام واحد — وهو الأفضل لأنماط الوصول المتوقعة
  • Include مع التصفية: يحمّل مجموعة فرعية فقط من العناصر الفرعية — في EF Core 5+
  • التحميل الكسول: مريح لكنه محفوف بالمخاطر — تجنّبه داخل الحلقات بسبب مشكلة N+1
  • التحميل الصريح: يحمّل البيانات عند الطلب مع تحكم دقيق
  • الإسقاط باستخدام Select: الأكثر كفاءة في السيناريوهات التي تقتصر على القراءة
  • الاستعلامات المنقسمة: تتجنب التضخم الكارتيزي عند تضمين مجموعات متعددة

الأسئلة الشائعة

هل درس «التحميل المبكر والكسول والصريح» مجاني؟

نعم — نص درس «التحميل المبكر والكسول والصريح» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة C# Academy، انتقل إلى CoddyKit PRO. تتضمن دورة C# Academy 4 دروس في المجموع.

ماذا ستتعلم في «التحميل المبكر والكسول والصريح»؟

تحكّموا في وقت تحميل البيانات المرتبطة باستخدام Include وThenInclude ووكلاء التحميل الكسول واستدعاءات Load الصريحة. تتمرن على C# Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ C# Academy؟

لا تُشترط خبرة سابقة. C# Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 1 من أصل 4.

كم من الوقت يستغرق درس «التحميل المبكر والكسول والصريح»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس C# Academy هذا؟

نعم. كل درس في C# Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. التحميل المبكر والكسول والصريح
  2. SQL خام والإجراءات المخزّنة والاستيفاء
  3. الاستعلامات المجمّعة والأداء
  4. عوامل تصفية الاستعلام العامة والكيانات المملوكة
← العودة إلى C# Academy