0Pricing
C# Academy · Pelajaran

Filter Kueri Global & Entitas Owned

Terapkan isolasi penyewa dan soft-delete dengan filter kueri global, lalu petakan objek nilai menggunakan tipe entitas owned.

Filter Kueri Global & Entitas Owned adalah pelajaran C# Academy gratis di CoddyKit. Ini adalah pelajaran 4 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar C# Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus C# Academy mencakup 4 pelajaran total.

Apa Itu Filter Kueri Global

Filter kueri global adalah predikat WHERE yang otomatis diterapkan ke setiap kueri LINQ untuk jenis entitas tertentu. Filter ini sangat cocok untuk penghapusan lunak, multitenansi, dan keamanan tingkat baris — tanpa perlu mengulangi kondisi di mana-mana.

Penghapusan Lunak dengan Filter Global

Tambahkan tanda IsDeleted dan konfigurasi filter global agar rekaman yang dihapus tidak pernah dikembalikan, kecuali Anda mengabaikan filter tersebut secara eksplisit.

// 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();

Multitenansi dengan Filter Global

Gunakan filter yang membaca penyewa saat ini dari layanan bercakupan. Setiap kueri otomatis dibatasi pada data penyewa saat ini.

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

Mengabaikan Filter Global

Terkadang Anda perlu melewati filter — misalnya, untuk kueri administrator atas semua penyewa atau untuk memulihkan rekaman yang dihapus secara lunak. Gunakan IgnoreQueryFilters() hanya untuk kueri tersebut.

// 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();
}

Filter pada Properti Navigasi

Filter global juga berpengaruh pada JOIN. Jika entitas Post memiliki filter, Post terkait yang dimuat melalui Include juga otomatis difilter.

// 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

Konsep Jenis Entitas Milik

Jenis entitas milik adalah kelas yang secara eksklusif dimiliki oleh satu entitas pemilik. Jenis ini tidak memiliki kunci utama dan secara bawaan disimpan dalam tabel yang sama. Jenis ini sangat cocok untuk objek nilai dalam 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; } = "";
}

Mengonfigurasi Entitas Milik

Gunakan OwnsOne untuk mengonfigurasi satu entitas milik. Secara bawaan, EF Core memberi awalan pada kolom dengan nama properti navigasi.

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, ...

Entitas Milik dalam Tabel Terpisah

Gunakan ToTable() di dalam OwnsOne untuk menyimpan entitas milik di tabelnya sendiri — berguna jika datanya besar atau bersifat opsional.

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 untuk Koleksi Objek Nilai

OwnsMany mengonfigurasi koleksi entitas milik — misalnya, daftar alamat email atau nomor telepon yang disimpan dalam tabel turunan.

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"));

Per-Tabel-Berdasarkan-Hierarki vs Entitas Milik

Filter global juga berfungsi baik dengan pewarisan TPH (per tabel berdasarkan hierarki), di mana kolom diskriminator membedakan subjenis. Terapkan filter berdasarkan diskriminator untuk kueri khusus jenis.

// 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'

Dunia Nyata: Isolasi Penyewa SaaS

Penyiapan multitenansi SaaS yang lengkap menggabungkan filter kueri global dengan konteks penyewa bercakupan, sehingga setiap kueri otomatis dibatasi tanpa kode khusus untuk setiap kueri.

// 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'

Pemeriksaan Singkat

Metode apa yang Anda panggil untuk sementara melewati filter kueri global pada kueri tertentu?

Ringkasan: Filter Global & Entitas Milik

Hal-hal penting:

  • Filter kueri global secara otomatis menambahkan predikat WHERE ke setiap kueri untuk suatu entitas
  • Sangat ideal untuk penghapusan lunak, multitenansi, dan keamanan tingkat baris
  • Lewati dengan IgnoreQueryFilters() untuk operasi administrator atau pemulihan
  • Entitas milik memodelkan objek nilai — tanpa PK, disimpan dalam tabel pemilik
  • OwnsOne / OwnsMany mengonfigurasi relasi entitas milik; gunakan ToTable() untuk memisahkannya

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Filter Kueri Global & Entitas Owned” gratis?

Ya — teks lengkap “Filter Kueri Global & Entitas Owned” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus C# Academy, upgrade ke CoddyKit PRO. Kursus C# Academy mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Filter Kueri Global & Entitas Owned”?

Terapkan isolasi penyewa dan soft-delete dengan filter kueri global, lalu petakan objek nilai menggunakan tipe entitas owned. Kamu berlatih C# Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai C# Academy?

Tidak diperlukan pengalaman sebelumnya. C# Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 4 dari 4.

Berapa lama pelajaran “Filter Kueri Global & Entitas Owned” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran C# Academy ini?

Ya. Setiap pelajaran C# Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. Pemuatan Eager, Lazy & Eksplisit
  2. SQL Mentah, Prosedur Tersimpan & Interpolasi
  3. Kueri Terkompilasi & Performa
  4. Filter Kueri Global & Entitas Owned
← Kembali ke C# Academy