C# Academy · درس

عوامل تصفية الاستعلام العامة والكيانات المملوكة

طبّقوا عزل المستأجرين والحذف المنطقي باستخدام عوامل تصفية الاستعلام العامة، واربطوا كائنات القيم باستخدام أنواع الكيانات المملوكة.

الدرس 4 من 413 خطوة

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

ما عوامل تصفية الاستعلامات العامة؟

عوامل تصفية الاستعلامات العامة هي شروط WHERE تُطبَّق تلقائيًا على كل استعلام LINQ لنوع كيان معين. وهي مثالية لـالحذف المنطقي وتعدد المستأجرين والأمان على مستوى الصف، من دون تكرار الشرط في كل موضع.

الحذف المنطقي باستخدام عامل تصفية عام

أضف علامة IsDeleted وتهيئة عامل تصفية عام بحيث لا تُرجع السجلات المحذوفة أبدًا، إلا إذا تجاهلت عامل التصفية صراحةً.

// Entity with soft-delete flag
public class Post
{
    public int Id { get; set; }
    public string Title { get; set; } = "";
    public bool IsDeleted { get; set; }
}

// Configure in OnModelCreating
modelBuilder.Entity<Post>()
    .HasQueryFilter(p => !p.IsDeleted);

// All queries now implicitly add WHERE IsDeleted = 0:
var posts = await _db.Posts.ToListAsync();

تعدد المستأجرين باستخدام عامل تصفية عام

استخدم عامل تصفية يقرأ المستأجر الحالي من خدمة محددة النطاق. وسيُقيَّد كل استعلام تلقائيًا ببيانات المستأجر الحالي.

public class AppDbContext : DbContext
{
    private readonly ICurrentUserService _user;

    public AppDbContext(DbContextOptions<AppDbContext> opt, ICurrentUserService user)
        : base(opt) => _user = user;

    protected override void OnModelCreating(ModelBuilder mb)
    {
        mb.Entity<Order>().HasQueryFilter(
            o => o.TenantId == _user.TenantId);
    }
}
// Every Order query automatically filters by TenantId

تجاهل عوامل التصفية العامة

قد تحتاج أحيانًا إلى تجاوز عامل التصفية، مثل استعلامات المسؤولين عن جميع المستأجرين أو استعادة سجل محذوف منطقيًا. استخدم IgnoreQueryFilters() لهذا الاستعلام فقط.

// Admin: see ALL posts including deleted
var allPosts = await _db.Posts
    .IgnoreQueryFilters()
    .ToListAsync();

// Restore a specific deleted post
var deleted = await _db.Posts
    .IgnoreQueryFilters()
    .FirstOrDefaultAsync(p => p.Id == 42);

if (deleted is not null)
{
    deleted.IsDeleted = false;
    await _db.SaveChangesAsync();
}

عوامل التصفية على خصائص التنقل

تشارك عوامل التصفية العامة أيضًا في عمليات JOIN. فإذا كان Posts يتضمن عامل تصفية، فستُصفّى تلقائيًا أيضًا كائنات Posts المرتبطة التي تُحمّل عبر Include.

// Blog with soft-delete filter on Posts
var blog = await _db.Blogs
    .Include(b => b.Posts) // only non-deleted posts are included
    .FirstOrDefaultAsync(b => b.Id == 1);

// blog.Posts contains only active posts — the filter applied in the JOIN

أنواع الكيانات المملوكة: المفهوم

أنواع الكيانات المملوكة هي أصناف تنتمي حصريًا إلى كيان مالك واحد. ولا تملك مفتاحًا أساسيًا، وتُخزَّن في الجدول نفسه افتراضيًا. وهي مناسبة جدًا لكائنات القيمة في DDD.

public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; } = "";
    public Address BillingAddress  { get; set; } = new();
    public Address ShippingAddress { get; set; } = new();
}

public class Address
{
    public string Street  { get; set; } = "";
    public string City    { get; set; } = "";
    public string ZipCode { get; set; } = "";
    public string Country { get; set; } = "";
}

تهيئة الكيانات المملوكة

استخدم OwnsOne لتهيئة كيان مملوك واحد. ويضع EF Core اسم خاصية التنقل قبل أسماء الأعمدة افتراضيًا.

modelBuilder.Entity<Customer>(entity =>
{
    entity.OwnsOne(c => c.BillingAddress, addr =>
    {
        addr.Property(a => a.Street).HasMaxLength(300);
        addr.Property(a => a.Country).HasMaxLength(2);
    });

    entity.OwnsOne(c => c.ShippingAddress);
});
// Table: Customers with columns:
// BillingAddress_Street, BillingAddress_City, ...
// ShippingAddress_Street, ShippingAddress_City, ...

الكيانات المملوكة في جدول منفصل

استخدم ToTable() داخل OwnsOne لتخزين الكيانات المملوكة في جدولها الخاص، وهو ما يفيد عندما تكون البيانات كبيرة أو اختيارية.

modelBuilder.Entity<Customer>().OwnsOne(
    c => c.BillingAddress,
    addr => addr.ToTable("CustomerBillingAddresses"));

// Now BillingAddress columns are in a separate table
// with a FK back to CustomerId

OwnsMany لمجموعات كائنات القيمة

تهيّئ OwnsMany مجموعة من الكيانات المملوكة، مثل قائمة بعناوين البريد الإلكتروني أو أرقام الهواتف المخزنة في جدول فرعي.

public class Customer
{
    public int Id { get; set; }
    public IList<PhoneNumber> PhoneNumbers { get; set; } = new List<PhoneNumber>();
}

public class PhoneNumber
{
    public string Number { get; set; } = "";
    public string Type   { get; set; } = "";
}

modelBuilder.Entity<Customer>()
    .OwnsMany(c => c.PhoneNumbers,
        phone => phone.ToTable("CustomerPhones"));

جدول لكل تسلسل هرمي مقارنةً بالكيانات المملوكة

تعمل عوامل التصفية العامة جيدًا أيضًا مع الوراثة باستخدام TPH (جدول لكل تسلسل هرمي)، حيث يميّز عمود تمييز بين الأنواع الفرعية. طبّق عامل تصفية يستند إلى عمود التمييز للاستعلامات الخاصة بنوع معين.

// Base entity
public abstract class Payment { public int Id { get; set; } }
public class CardPayment  : Payment { public string CardLast4 { get; set; } = ""; }
public class BankPayment  : Payment { public string IBAN { get; set; } = ""; }

// All Payment subtypes in one table with a Discriminator column
// No extra config needed — EF Core handles TPH by default
var cards = await _db.Set<CardPayment>().ToListAsync();
// SQL: SELECT * FROM Payments WHERE Discriminator = 'CardPayment'

عمليًا: عزل المستأجرين في SaaS

يجمع إعداد كامل لتعدد المستأجرين في SaaS بين عوامل تصفية الاستعلامات العامة وسياق مستأجر محدد النطاق، ما يضمن تقييد كل استعلام تلقائيًا من دون الحاجة إلى تعليمات خاصة بكل استعلام.

// Scoped tenant service
public class TenantContext
{
    public Guid TenantId { get; set; }
}

// DbContext uses it
modelBuilder.Entity<Invoice>().HasQueryFilter(
    inv => inv.TenantId == _tenantCtx.TenantId);
modelBuilder.Entity<Customer>().HasQueryFilter(
    c => c.TenantId == _tenantCtx.TenantId);

// Queries are automatically scoped:
var invoices = await _db.Invoices.ToListAsync();
// WHERE TenantId = 'current-tenant-guid'

تحقق سريع

ما الأسلوب الذي تستدعيه لتجاوز عامل تصفية استعلام عام مؤقتًا لاستعلام معين؟

مراجعة: عوامل التصفية العامة والكيانات المملوكة

أهم النقاط:

  • تضيف عوامل تصفية الاستعلامات العامة شروط WHERE تلقائيًا إلى كل استعلام لكيان معين
  • وهي مثالية للحذف المنطقي وتعدد المستأجرين والأمان على مستوى الصف
  • تجاوزها باستخدام IgnoreQueryFilters() لعمليات المسؤول أو الاستعادة
  • تمثّل الكيانات المملوكة كائنات القيمة — من دون مفتاح أساسي ومخزنة في جدول المالك
  • تهيّئ OwnsOne / OwnsMany العلاقات المملوكة؛ واستخدم ToTable() للفصل في جداول مستقلة
البدء مجانًا

تعلم C# مع معلم ذكاء اصطناعي — مجانًا

اكتب وقم بتشغيل أكوادك الفعلية في المتصفح، واحصل على مساعدة فورية من معلم ذكاء اصطناعي متاح 24/7، واستمر من حيث توقفت على الويب أو في التطبيق.

الدورات
93
الدروس
346

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

هل درس «عوامل تصفية الاستعلام العامة والكيانات المملوكة» مجاني؟

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

ماذا ستتعلم في «عوامل تصفية الاستعلام العامة والكيانات المملوكة»؟

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

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

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

كم من الوقت يستغرق درس «عوامل تصفية الاستعلام العامة والكيانات المملوكة»؟

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

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

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

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

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