Filtri globali per le query ed entità possedute
Applichi l'isolamento dei tenant e la cancellazione logica con i filtri globali per le query e mappi gli oggetti valore usando i tipi di entità possedute.
Filtri globali per le query ed entità possedute è una lezione C# Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento C# Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso C# Academy include 4 lezioni in totale.
Che cosa sono i filtri globali delle query?
I filtri globali delle query sono predicati WHERE applicati automaticamente a ogni query LINQ per un determinato tipo di entità. Sono perfetti per la cancellazione logica, la multi-tenancy e la sicurezza a livello di riga, senza dover ripetere la condizione ovunque.
Cancellazione logica con un filtro globale
Aggiunga un flag IsDeleted e configuri un filtro globale, in modo che i record eliminati non vengano mai restituiti a meno che non ignori esplicitamente il filtro.
// 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();Multi-tenancy con un filtro globale
Utilizzi un filtro che legge il tenant corrente da un servizio con durata scoped. Ogni query viene automaticamente limitata ai dati del tenant corrente.
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 TenantIdIgnorare i filtri globali
A volte è necessario ignorare il filtro, ad esempio per le query di amministrazione su tutti i tenant o per ripristinare un record eliminato logicamente. Utilizzi IgnoreQueryFilters() solo per quella query.
// 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();
}Filtri sulle proprietà di navigazione
I filtri globali partecipano anche ai JOIN. Se Posts ha un filtro, anche i Posts correlati caricati tramite Include vengono filtrati automaticamente.
// 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 JOINTipi di entità possedute: concetto
I tipi di entità possedute sono classi appartenenti esclusivamente a una singola entità proprietaria. Non hanno una chiave primaria e, per impostazione predefinita, vengono archiviate nella stessa tabella. Sono perfette per modellare gli oggetti valore nel 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; } = "";
}Configurare le entità possedute
Utilizzi OwnsOne per configurare una singola entità posseduta. Per impostazione predefinita, EF Core antepone alle colonne il nome della proprietà di navigazione.
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, ...Entità possedute in una tabella separata
Utilizzi ToTable() all'interno di OwnsOne per archiviare le entità possedute in una tabella dedicata, una soluzione utile quando i dati sono numerosi o facoltativi.
modelBuilder.Entity<Customer>().OwnsOne(
c => c.BillingAddress,
addr => addr.ToTable("CustomerBillingAddresses"));
// Now BillingAddress columns are in a separate table
// with a FK back to CustomerIdOwnsMany per raccolte di oggetti valore
OwnsMany configura una raccolta di entità possedute, ad esempio un elenco di indirizzi e-mail o numeri di telefono archiviati in una tabella figlia.
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"));Table-Per-Hierarchy e entità possedute
I filtri globali funzionano bene anche con l'ereditarietà TPH (Table-Per-Hierarchy), in cui una colonna discriminatore distingue i sottotipi. Applichi un filtro basato sul discriminatore per le query specifiche di un tipo.
// 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'Nella pratica: isolamento dei tenant SaaS
Una configurazione completa di multi-tenancy SaaS combina i filtri globali delle query con un contesto del tenant con durata scoped, garantendo che ogni query venga automaticamente limitata senza codice specifico per la singola query.
// 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'Verifica rapida
Quale metodo si richiama per ignorare temporaneamente un filtro globale delle query per una query specifica?
Riepilogo: filtri globali ed entità possedute
Punti chiave:
- I filtri globali delle query aggiungono automaticamente predicati WHERE a ogni query per un'entità
- Sono ideali per la cancellazione logica, la multi-tenancy e la sicurezza a livello di riga
- Si possono ignorare con
IgnoreQueryFilters()per le operazioni di amministrazione o ripristino - Le entità possedute modellano gli oggetti valore: non hanno una PK e vengono archiviate nella tabella dell'entità proprietaria
OwnsOne/OwnsManyconfigurano le relazioni con entità possedute; utilizziToTable()per separarle
Impara C# con un tutor IA — gratis
Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.
- Corsi
- 93
- Lezioni
- 346
Domande Frequenti
La lezione «Filtri globali per le query ed entità possedute» è gratuita?
Sì — il testo completo di «Filtri globali per le query ed entità possedute» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso C# Academy, passa a CoddyKit PRO. Il corso C# Academy include 4 lezioni in totale.
Cosa imparerò in «Filtri globali per le query ed entità possedute»?
Applichi l'isolamento dei tenant e la cancellazione logica con i filtri globali per le query e mappi gli oggetti valore usando i tipi di entità possedute. Eserciti C# Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare C# Academy?
Non è richiesta alcuna esperienza precedente. C# Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.
Quanto tempo richiede la lezione «Filtri globali per le query ed entità possedute»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione C# Academy?
Sì. Ogni lezione C# Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Caricamento eager, lazy ed esplicito
- SQL nativo, stored procedure e interpolazione
- Query compilate e prestazioni
- Filtri globali per le query ed entità possedute