[{"data":1,"prerenderedAt":111},["ShallowReactive",2],{"qa-\u002Fdotnet\u002Fentity-framework\u002Fdbcontext-dbset":3},{"page":4,"siblings":95,"blog":108},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":20,"path":21,"questions":22,"questionsCount":85,"related":86,"seo":87,"seoDescription":88,"stem":89,"subtopic":90,"topic":91,"topicSlug":92,"updated":93,"__hash__":94},"qa\u002Fdotnet\u002Fentity-framework\u002Fdbcontext-dbset.md","Dbcontext Dbset",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"medium","md",".NET Core","dotnet",{},true,1,"\u002Fdotnet\u002Fentity-framework\u002Fdbcontext-dbset",[23,28,32,36,40,44,48,52,56,60,64,68,72,76,81],{"id":24,"difficulty":25,"q":26,"a":27},"ef-dbcontext-role","easy","What is DbContext and what role does it play in EF Core?","**`DbContext`** is the primary entry point for EF Core. It combines three patterns:\n**Unit of Work** (batches changes), **Repository** (queries via `DbSet\u003CT>`), and\n**Identity Map** (tracks entity instances by primary key within the same scope).\n\n```csharp\n\u002F\u002F Define your context by deriving from DbContext:\npublic class AppDbContext : DbContext\n{\n    \u002F\u002F Each DbSet\u003CT> maps to a table — the query surface for that entity:\n    public DbSet\u003COrder>   Orders   { get; set; }\n    public DbSet\u003CProduct> Products { get; set; }\n    public DbSet\u003CCustomer> Customers { get; set; }\n\n    public AppDbContext(DbContextOptions\u003CAppDbContext> options)\n        : base(options) { }\n\n    protected override void OnModelCreating(ModelBuilder modelBuilder)\n    {\n        \u002F\u002F Fluent API configuration lives here:\n        modelBuilder.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);\n    }\n}\n\n\u002F\u002F Register in Program.cs — the container creates a new instance per request:\nbuilder.Services.AddDbContext\u003CAppDbContext>(options =>\n    options.UseSqlServer(builder.Configuration.GetConnectionString(\"Default\")));\n\n\u002F\u002F Inject and use in a service:\npublic class OrderService\n{\n    private readonly AppDbContext _db;\n    public OrderService(AppDbContext db) => _db = db;\n\n    public async Task\u003COrder?> GetOrderAsync(int id)\n        => await _db.Orders.FindAsync(id); \u002F\u002F uses identity map first\n}\n```\n\n**Rule of thumb:** `DbContext` is a scoped service — one instance per HTTP request.\nNever register it as Singleton; the change tracker is not thread-safe.\n",{"id":29,"difficulty":25,"q":30,"a":31},"ef-dbset-operations","What operations does DbSet\u003CT> expose and how do they map to SQL?","**`DbSet\u003CT>`** is the query and change surface for one entity type. LINQ methods\non it build SQL; add\u002Fremove\u002Fupdate methods stage changes in the change tracker.\n\n```csharp\n\u002F\u002F Querying — translated to SQL by EF Core's query pipeline:\nvar orders = await _db.Orders\n    .Where(o => o.CustomerId == customerId)   \u002F\u002F WHERE\n    .OrderByDescending(o => o.CreatedAt)      \u002F\u002F ORDER BY\n    .Take(20)                                  \u002F\u002F TOP 20\n    .ToListAsync();                            \u002F\u002F executes → SELECT\n\n\u002F\u002F Find by primary key (checks identity map before hitting DB):\nvar order = await _db.Orders.FindAsync(42);\n\n\u002F\u002F Staging changes — do NOT hit the DB until SaveChanges:\n_db.Orders.Add(new Order { CustomerId = 1 });    \u002F\u002F INSERT\n_db.Orders.Update(existingOrder);                \u002F\u002F UPDATE (all columns)\n_db.Orders.Remove(existingOrder);                \u002F\u002F DELETE\n\n\u002F\u002F SaveChanges wraps all staged ops in one transaction:\nawait _db.SaveChangesAsync();\n\n\u002F\u002F Direct SQL for non-LINQ operations:\nvar orders = await _db.Orders\n    .FromSqlRaw(\"SELECT * FROM Orders WHERE Status = {0}\", \"Pending\")\n    .ToListAsync();\n\n\u002F\u002F ExecuteSqlRawAsync for non-query statements (INSERT\u002FUPDATE\u002FDELETE):\nawait _db.Database.ExecuteSqlRawAsync(\n    \"DELETE FROM Orders WHERE CreatedAt \u003C {0}\", cutoff);\n```\n\n**Rule of thumb:** Use LINQ on `DbSet\u003CT>` for queries — EF translates it to\noptimised SQL. Fall back to `FromSqlRaw` or `ExecuteSqlRawAsync` only for\noperations LINQ can't express.\n",{"id":33,"difficulty":25,"q":34,"a":35},"ef-dbcontextoptions","How do you configure DbContextOptions and what provider options are available?","**`DbContextOptions\u003CTContext>`** carries the provider choice, connection string,\nand behaviour options. It's set during registration and injected into the context\nconstructor.\n\n```csharp\n\u002F\u002F SQL Server:\nbuilder.Services.AddDbContext\u003CAppDbContext>(options =>\n    options.UseSqlServer(\n        builder.Configuration.GetConnectionString(\"Default\"),\n        sql => sql.CommandTimeout(60)    \u002F\u002F per-query timeout in seconds\n                  .MigrationsAssembly(\"MyApp.Data\") \u002F\u002F separate assembly\n    ));\n\n\u002F\u002F SQLite (dev \u002F tests):\nbuilder.Services.AddDbContext\u003CAppDbContext>(options =>\n    options.UseSqlite(\"Data Source=app.db\"));\n\n\u002F\u002F PostgreSQL (Npgsql):\nbuilder.Services.AddDbContext\u003CAppDbContext>(options =>\n    options.UseNpgsql(connectionString));\n\n\u002F\u002F In-memory (tests only — not a real DB; no transactions or constraints):\nbuilder.Services.AddDbContext\u003CAppDbContext>(options =>\n    options.UseInMemoryDatabase(\"TestDb\"));\n\n\u002F\u002F Add diagnostics in development:\nif (builder.Environment.IsDevelopment())\n{\n    options.EnableSensitiveDataLogging(); \u002F\u002F shows param values in logs\n    options.EnableDetailedErrors();        \u002F\u002F richer error messages\n}\n\n\u002F\u002F Manual construction (e.g., in a factory):\nvar opts = new DbContextOptionsBuilder\u003CAppDbContext>()\n    .UseSqlServer(connectionString)\n    .Options;\n\nusing var db = new AppDbContext(opts);\n```\n\n**Rule of thumb:** Use `AddDbContext\u003CT>` for web apps — it handles lifetime and\ndisposal. Build `DbContextOptions` manually only in tests or migration tooling.\n",{"id":37,"difficulty":14,"q":38,"a":39},"ef-change-tracking","How does EF Core's change tracker work and what entity states are there?","The **change tracker** watches entity instances and records mutations so\n`SaveChanges` can generate the correct SQL without you specifying it.\n\n```csharp\n\u002F\u002F Entity states:\n\u002F\u002F Added    → INSERT on SaveChanges\n\u002F\u002F Modified → UPDATE on SaveChanges\n\u002F\u002F Deleted  → DELETE on SaveChanges\n\u002F\u002F Unchanged→ no SQL\n\u002F\u002F Detached → not tracked at all\n\nvar order = await _db.Orders.FindAsync(42); \u002F\u002F state: Unchanged\norder.Status = \"Shipped\";                   \u002F\u002F state: Modified (detected automatically)\nawait _db.SaveChangesAsync();               \u002F\u002F generates: UPDATE Orders SET Status=... WHERE Id=42\n\n\u002F\u002F Manual state management:\n_db.Entry(order).State = EntityState.Modified; \u002F\u002F mark all columns dirty\n_db.Entry(order).Property(o => o.Status).IsModified = true; \u002F\u002F only one column\n\n\u002F\u002F Inspect current state:\nConsole.WriteLine(_db.Entry(order).State); \u002F\u002F EntityState.Modified\n\n\u002F\u002F AsNoTracking — read-only queries; no change tracker overhead:\nvar orders = await _db.Orders\n    .AsNoTracking()\n    .Where(o => o.Status == \"Pending\")\n    .ToListAsync();\n\u002F\u002F Useful for read-heavy endpoints — faster, lower memory usage\n\n\u002F\u002F Attach a detached entity and mark it modified:\n_db.Orders.Attach(detachedOrder);\n_db.Entry(detachedOrder).State = EntityState.Modified;\nawait _db.SaveChangesAsync();\n```\n\n**Rule of thumb:** Use `AsNoTracking()` on read-only queries — it skips change\ntracker overhead and is measurably faster. Only track entities you intend to mutate.\n",{"id":41,"difficulty":14,"q":42,"a":43},"ef-savechanges","How does SaveChanges work and what happens under the hood?","**`SaveChanges`** \u002F **`SaveChangesAsync`** inspects the change tracker, generates\nSQL for every `Added`, `Modified`, and `Deleted` entity, and executes all of them\nin a **single implicit transaction**.\n\n```csharp\n\u002F\u002F Everything between two SaveChanges calls is one unit of work:\nvar customer = new Customer { Name = \"Alice\" };\n_db.Customers.Add(customer);                  \u002F\u002F queued: INSERT Customer\n\nvar product = await _db.Products.FindAsync(5);\nproduct.Stock -= 1;                            \u002F\u002F queued: UPDATE Product\n\nvar order = new Order { CustomerId = customer.Id, ProductId = 5 };\n_db.Orders.Add(order);                         \u002F\u002F queued: INSERT Order\n\n\u002F\u002F One round trip — all three ops in one transaction:\nint rows = await _db.SaveChangesAsync();       \u002F\u002F returns count of affected rows\n\n\u002F\u002F Manual transaction for multiple SaveChanges calls:\nawait using var tx = await _db.Database.BeginTransactionAsync();\ntry\n{\n    _db.Orders.Add(order);\n    await _db.SaveChangesAsync();          \u002F\u002F first save — inside tx\n\n    _db.Invoices.Add(invoice);\n    await _db.SaveChangesAsync();          \u002F\u002F second save — same tx\n\n    await tx.CommitAsync();\n}\ncatch\n{\n    await tx.RollbackAsync();\n    throw;\n}\n\n\u002F\u002F Intercept every save with SaveChangesInterceptor:\npublic class AuditInterceptor : SaveChangesInterceptor\n{\n    public override ValueTask\u003CInterceptionResult\u003Cint>> SavingChangesAsync(...)\n    {\n        foreach (var entry in context.ChangeTracker.Entries\u003CIAuditable>())\n            entry.Entity.UpdatedAt = DateTime.UtcNow; \u002F\u002F stamp before save\n        return base.SavingChangesAsync(...);\n    }\n}\n```\n\n**Rule of thumb:** Call `SaveChangesAsync` once per logical operation. Multiple\n`SaveChanges` calls in one request need an explicit transaction to stay atomic.\n",{"id":45,"difficulty":14,"q":46,"a":47},"ef-dbcontext-lifetime","Why should DbContext be registered as Scoped, not Singleton or Transient?","**`DbContext` is stateful** — the change tracker holds entity references tied to a\nspecific database connection. Registering it wrong causes data corruption or leaks.\n\n```csharp\n\u002F\u002F Scoped (correct) — one DbContext per HTTP request:\nbuilder.Services.AddDbContext\u003CAppDbContext>(options =>\n    options.UseSqlServer(connectionString));\n\u002F\u002F Default lifetime from AddDbContext is Scoped.\n\u002F\u002F Each request gets its own change tracker and connection.\n\n\u002F\u002F Singleton — DbContext shared across ALL requests concurrently:\n\u002F\u002F - Change tracker corrupted by overlapping requests.\n\u002F\u002F - Connection held open forever → exhausts the pool.\n\u002F\u002F - First writer's uncommitted data visible to other requests.\n\n\u002F\u002F Transient — new DbContext for every injection within a request:\n\u002F\u002F - An entity modified in ServiceA's context is NOT visible in ServiceB's context.\n\u002F\u002F - SaveChanges in ServiceA doesn't commit ServiceB's work.\n\u002F\u002F - Double the connection pool usage per request.\n\n\u002F\u002F Background services must create their own scope:\npublic class ReportWorker : BackgroundService\n{\n    private readonly IServiceScopeFactory _scopeFactory;\n    public ReportWorker(IServiceScopeFactory scopeFactory)\n        => _scopeFactory = scopeFactory;\n\n    protected override async Task ExecuteAsync(CancellationToken ct)\n    {\n        using var scope = _scopeFactory.CreateScope();\n        var db = scope.ServiceProvider.GetRequiredService\u003CAppDbContext>();\n        \u002F\u002F db is a fresh, properly scoped context for this job\n    }\n}\n```\n\n**Rule of thumb:** `DbContext` must be Scoped. Background services and singletons\nmust never inject it directly — use `IServiceScopeFactory` instead.\n",{"id":49,"difficulty":14,"q":50,"a":51},"ef-connection-pooling","What is DbContext pooling and when should you use it?","**`AddDbContextPool`** reuses `DbContext` instances from a pool rather than\ncreating a new one per request — removing the allocation and garbage collection\ncost per context (though EF Core resets the instance before reuse).\n\n```csharp\n\u002F\u002F Standard — creates a new AppDbContext per request:\nbuilder.Services.AddDbContext\u003CAppDbContext>(options =>\n    options.UseSqlServer(connectionString));\n\n\u002F\u002F Pooled — reuses instances from a pool (default size: 1024):\nbuilder.Services.AddDbContextPool\u003CAppDbContext>(options =>\n    options.UseSqlServer(connectionString),\n    poolSize: 128);        \u002F\u002F tune to expected concurrency\n\n\u002F\u002F Constraints with pooling:\n\u002F\u002F 1. AppDbContext constructor MUST accept only DbContextOptions — no extra injected deps.\n\u002F\u002F If you need IConfiguration, use the IDbContextFactory pattern instead.\n\u002F\u002F 2. OnConfiguring is called once, not per-request — configuration must be in options.\n\u002F\u002F 3. EF resets state (change tracker, transactions) but custom fields are NOT reset.\n\u002F\u002F Store no request-specific state in the context.\n\n\u002F\u002F IDbContextFactory — create short-lived contexts on demand (e.g. in Blazor Server):\nbuilder.Services.AddDbContextFactory\u003CAppDbContext>(options =>\n    options.UseSqlServer(connectionString));\n\npublic class ProductImporter\n{\n    private readonly IDbContextFactory\u003CAppDbContext> _factory;\n    public ProductImporter(IDbContextFactory\u003CAppDbContext> factory)\n        => _factory = factory;\n\n    public async Task ImportAsync(IEnumerable\u003CProduct> products)\n    {\n        await using var db = await _factory.CreateDbContextAsync();\n        db.Products.AddRange(products);\n        await db.SaveChangesAsync();\n    } \u002F\u002F context disposed here — safe in Blazor Server long-lived components\n}\n```\n\n**Rule of thumb:** Use `AddDbContextPool` for high-throughput APIs where context\ncreation is a measurable overhead. Use `IDbContextFactory` in Blazor Server or\nbackground jobs that need fine-grained context lifetime control.\n",{"id":53,"difficulty":14,"q":54,"a":55},"ef-onconfiguring-vs-adddbcontext","What is the difference between configuring EF Core via OnConfiguring vs AddDbContext?","**`OnConfiguring`** is the context's own method for self-configuring; **`AddDbContext`**\nconfigures externally via DI. The two approaches differ in testability and coupling.\n\n```csharp\n\u002F\u002F OnConfiguring — hardcodes provider; can't swap in tests:\npublic class AppDbContext : DbContext\n{\n    protected override void OnConfiguring(DbContextOptionsBuilder builder)\n    {\n        \u002F\u002F Connection string hardcoded; no way to inject a test database:\n        builder.UseSqlServer(\"Server=prod;Database=App;...\");\n    }\n}\n\n\u002F\u002F Constructor injection + AddDbContext (preferred):\npublic class AppDbContext : DbContext\n{\n    public AppDbContext(DbContextOptions\u003CAppDbContext> options)\n        : base(options) { }   \u002F\u002F options come from the DI container\n\n    protected override void OnModelCreating(ModelBuilder mb)\n    {\n        mb.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);\n    }\n}\n\n\u002F\u002F Wire-up in Program.cs — swap to SQLite in tests without changing the context:\nbuilder.Services.AddDbContext\u003CAppDbContext>(o =>\n    o.UseSqlServer(builder.Configuration.GetConnectionString(\"Default\")));\n\n\u002F\u002F Test setup:\nservices.AddDbContext\u003CAppDbContext>(o =>\n    o.UseSqlite(\"Data Source=:memory:\"));\n```\n\n`OnConfiguring` is only appropriate when the context is constructed manually\n(migration tooling, design-time factories).\n\n**Rule of thumb:** Never hardcode a connection string in `OnConfiguring` in\nproduction code. Pass `DbContextOptions` via the constructor so tests can inject\na different provider.\n",{"id":57,"difficulty":14,"q":58,"a":59},"ef-entity-configuration","How do you configure entity mappings in EF Core — data annotations vs Fluent API?","EF Core offers two mapping approaches: **data annotations** (attributes on the\nclass) and **Fluent API** (code in `OnModelCreating`). Fluent API is more powerful\nand keeps domain models free of infrastructure concerns.\n\n```csharp\n\u002F\u002F Data annotation approach — quick but pollutes the domain model:\n[Table(\"Orders\")]\npublic class Order\n{\n    [Key]\n    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]\n    public int Id { get; set; }\n\n    [Required]\n    [MaxLength(50)]\n    public string Status { get; set; } = \"\";\n\n    [Column(TypeName = \"decimal(18,2)\")]\n    public decimal Total { get; set; }\n}\n\n\u002F\u002F Fluent API approach — preferred; domain model stays clean:\npublic class OrderConfiguration : IEntityTypeConfiguration\u003COrder>\n{\n    public void Configure(EntityTypeBuilder\u003COrder> builder)\n    {\n        builder.ToTable(\"Orders\");\n        builder.HasKey(o => o.Id);\n        builder.Property(o => o.Status)\n               .IsRequired()\n               .HasMaxLength(50);\n        builder.Property(o => o.Total)\n               .HasColumnType(\"decimal(18,2)\");\n        builder.HasIndex(o => o.CustomerId); \u002F\u002F index on FK\n    }\n}\n\n\u002F\u002F Register all IEntityTypeConfiguration\u003CT> in one call:\nprotected override void OnModelCreating(ModelBuilder mb)\n    => mb.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);\n```\n\n**Rule of thumb:** Use Fluent API via `IEntityTypeConfiguration\u003CT>` and\n`ApplyConfigurationsFromAssembly`. It scales to large models and keeps entity\nclasses free of EF-specific attributes.\n",{"id":61,"difficulty":14,"q":62,"a":63},"ef-value-conversions","What are value conversions in EF Core and when do you use them?","**Value conversions** let EF Core convert a property value between its in-memory\nCLR type and the database column type — useful for enums, strongly typed IDs,\nJSON columns, and encrypted fields.\n\n```csharp\n\u002F\u002F Store an enum as a string instead of an int:\npublic enum OrderStatus { Pending, Shipped, Delivered, Cancelled }\n\nbuilder.Property(o => o.Status)\n       .HasConversion\u003Cstring>()   \u002F\u002F stores \"Pending\", not 0\n       .HasMaxLength(20);\n\n\u002F\u002F Strongly typed ID value object:\npublic record OrderId(int Value);\n\nbuilder.Property(o => o.Id)\n       .HasConversion(\n           id => id.Value,        \u002F\u002F CLR → DB\n           val => new OrderId(val)); \u002F\u002F DB → CLR\n\n\u002F\u002F JSON column (EF Core 7+) — stores a complex type as JSON:\nbuilder.OwnsOne(o => o.ShippingAddress, addr =>\n{\n    addr.ToJson(); \u002F\u002F stored as a JSON column — one column, full object\n});\n\n\u002F\u002F Custom converter class:\npublic class MoneyConverter : ValueConverter\u003CMoney, decimal>\n{\n    public MoneyConverter() : base(\n        m => m.Amount,              \u002F\u002F CLR → DB\n        d => new Money(d, \"USD\"))   \u002F\u002F DB → CLR\n    { }\n}\n\nbuilder.Property(o => o.Price)\n       .HasConversion(new MoneyConverter());\n```\n\n**Rule of thumb:** Use value conversions to keep your domain model clean and\nstrongly typed. Store enums as strings for readability in production databases;\nstore value objects with `HasConversion` or `ToJson` rather than flattening manually.\n",{"id":65,"difficulty":14,"q":66,"a":67},"ef-global-query-filters","What are global query filters and how do you use them for soft deletes?","**Global query filters** apply a `WHERE` clause automatically to every query on\nan entity — the standard EF Core mechanism for **soft deletes** and **multi-tenancy**.\n\n```csharp\n\u002F\u002F Entity with soft-delete flag:\npublic class Order\n{\n    public int Id { get; set; }\n    public bool IsDeleted { get; set; }\n    public int TenantId { get; set; }\n    \u002F\u002F ...\n}\n\n\u002F\u002F Register global filter in OnModelCreating:\nmodelBuilder.Entity\u003COrder>()\n    .HasQueryFilter(o => !o.IsDeleted);\n\u002F\u002F Every query: SELECT * FROM Orders WHERE IsDeleted = 0 — automatic\n\n\u002F\u002F Multi-tenancy filter (inject the current tenant via constructor):\npublic class AppDbContext : DbContext\n{\n    private readonly int _tenantId;\n\n    public AppDbContext(DbContextOptions\u003CAppDbContext> opts, ITenantContext tenant)\n        : base(opts)\n    {\n        _tenantId = tenant.CurrentTenantId;\n    }\n\n    protected override void OnModelCreating(ModelBuilder mb)\n    {\n        mb.Entity\u003COrder>().HasQueryFilter(o =>\n            !o.IsDeleted && o.TenantId == _tenantId);\n    }\n}\n\n\u002F\u002F Bypass the filter when needed (admin operations, data migration):\nvar allOrders = await _db.Orders\n    .IgnoreQueryFilters()      \u002F\u002F disables global filters for this query\n    .ToListAsync();\n\n\u002F\u002F Soft delete — just set the flag, don't call Remove:\norder.IsDeleted = true;\nawait _db.SaveChangesAsync(); \u002F\u002F UPDATE Orders SET IsDeleted=1 WHERE Id=...\n```\n\n**Rule of thumb:** Use global query filters for cross-cutting concerns (soft delete,\nmulti-tenancy) so they're applied consistently. Add `IgnoreQueryFilters()` only in\nexplicit admin or migration paths.\n",{"id":69,"difficulty":14,"q":70,"a":71},"ef-keyless-entity-types","What are keyless entity types in EF Core and when do you use them?","**Keyless entity types** (`HasNoKey`) map to database objects that have no primary\nkey — database views, raw SQL result sets, or tables used only for reporting. They\nare always read-only; EF Core never tracks or saves them.\n\n```csharp\n\u002F\u002F DTO mapped to a view (no primary key):\npublic class OrderSummaryView\n{\n    public int CustomerId { get; set; }\n    public string CustomerName { get; set; } = \"\";\n    public int OrderCount { get; set; }\n    public decimal TotalRevenue { get; set; }\n}\n\n\u002F\u002F Configuration — mark as keyless and point to the view:\nmodelBuilder.Entity\u003COrderSummaryView>(b =>\n{\n    b.HasNoKey();                          \u002F\u002F no PK — never tracked\n    b.ToView(\"vw_OrderSummaries\");         \u002F\u002F maps to a DB view\n});\n\n\u002F\u002F Expose via a DbSet property on the context:\npublic DbSet\u003COrderSummaryView> OrderSummaries { get; set; }\n\n\u002F\u002F Query exactly like any DbSet — fully composable:\nvar top10 = await _db.OrderSummaries\n    .AsNoTracking()\n    .OrderByDescending(v => v.TotalRevenue)\n    .Take(10)\n    .ToListAsync();\n\u002F\u002F SQL: SELECT TOP 10 ... FROM vw_OrderSummaries ORDER BY TotalRevenue DESC\n\n\u002F\u002F Use FromSqlRaw with a keyless type for arbitrary result shapes:\nvar results = await _db.OrderSummaries\n    .FromSqlRaw(\"EXEC sp_GetOrderSummaries @Year = {0}\", 2026)\n    .ToListAsync();\n```\n\n**Rule of thumb:** Use keyless entity types for read-only views and stored procedure\nresults. Never call `SaveChanges` with them — EF has no way to generate INSERT\u002FUPDATE\u002F\nDELETE without a primary key.\n",{"id":73,"difficulty":14,"q":74,"a":75},"ef-raw-queries-ef8","What is SqlQuery and how does it differ from FromSqlRaw in EF Core 8?","**`SqlQuery\u003CT>`** (EF Core 8+) executes raw SQL and maps results to any CLR type —\nincluding primitives and non-entity types — without requiring a `DbSet\u003CT>` or keyless\nentity registration. `FromSqlRaw` only works with types known to the EF model.\n\n```csharp\n\u002F\u002F FromSqlRaw — requires the type to be in the EF model (entity or keyless):\nvar orders = await _db.Orders\n    .FromSqlRaw(\"SELECT * FROM Orders WHERE Status = {0}\", \"Pending\")\n    .ToListAsync(); \u002F\u002F Order must be a tracked or keyless type\n\n\u002F\u002F SqlQuery\u003CT> (EF Core 8+) — works with any scalar or simple CLR type:\n\n\u002F\u002F Scalar: fetch a single value:\nvar count = await _db.Database\n    .SqlQuery\u003Cint>($\"SELECT COUNT(*) FROM Orders WHERE Status = 'Pending'\")\n    .SingleAsync();\n\n\u002F\u002F Primitive list:\nvar ids = await _db.Database\n    .SqlQuery\u003Cint>($\"SELECT Id FROM Orders WHERE Total > {threshold}\")\n    .ToListAsync();\n\n\u002F\u002F Anonymous-like DTO (must be a concrete class with matching property names):\npublic record StatusCount(string Status, int Count);\n\nvar breakdown = await _db.Database\n    .SqlQuery\u003CStatusCount>(\n        $\"SELECT Status, COUNT(*) AS Count FROM Orders GROUP BY Status\")\n    .ToListAsync();\n\n\u002F\u002F Compose LINQ on top (EF wraps it in a subquery):\nvar top = await _db.Database\n    .SqlQuery\u003CStatusCount>(\n        $\"SELECT Status, COUNT(*) AS Count FROM Orders GROUP BY Status\")\n    .OrderByDescending(r => r.Count)\n    .Take(3)\n    .ToListAsync();\n```\n\n**Rule of thumb:** Use `SqlQuery\u003CT>` when you need raw SQL that returns scalars,\nprimitives, or ad-hoc DTOs not registered in the EF model. Use `FromSqlRaw` when\nyou want to compose LINQ on top of a raw SQL fragment that returns a tracked entity type.\n",{"id":77,"difficulty":78,"q":79,"a":80},"ef-interceptors","hard","What are EF Core interceptors and how do you use them for auditing?","**Interceptors** hook into EF Core's internal pipeline at specific points — command\nexecution, connection events, and SaveChanges — without modifying entity classes.\n\n```csharp\n\u002F\u002F Auditing interceptor — stamp UpdatedAt before every save:\npublic class AuditInterceptor : SaveChangesInterceptor\n{\n    public override InterceptionResult\u003Cint> SavingChanges(\n        DbContextEventData eventData, InterceptionResult\u003Cint> result)\n    {\n        StampAuditFields(eventData.Context!);\n        return base.SavingChanges(eventData, result);\n    }\n\n    public override ValueTask\u003CInterceptionResult\u003Cint>> SavingChangesAsync(\n        DbContextEventData eventData, InterceptionResult\u003Cint> result,\n        CancellationToken ct = default)\n    {\n        StampAuditFields(eventData.Context!);\n        return base.SavingChangesAsync(eventData, result, ct);\n    }\n\n    private static void StampAuditFields(DbContext db)\n    {\n        var now = DateTime.UtcNow;\n        foreach (var entry in db.ChangeTracker.Entries\u003CIAuditable>())\n        {\n            if (entry.State == EntityState.Added)\n                entry.Entity.CreatedAt = now;\n            if (entry.State is EntityState.Added or EntityState.Modified)\n                entry.Entity.UpdatedAt = now;\n        }\n    }\n}\n\n\u002F\u002F Command interceptor — log slow queries:\npublic class SlowQueryInterceptor : DbCommandInterceptor\n{\n    public override DbDataReader ReaderExecuted(\n        DbCommand command, CommandExecutedEventData data, DbDataReader result)\n    {\n        if (data.Duration > TimeSpan.FromSeconds(1))\n            Console.WriteLine($\"SLOW QUERY ({data.Duration.TotalMs}ms): {command.CommandText}\");\n        return result;\n    }\n}\n\n\u002F\u002F Register interceptors on the context:\nbuilder.Services.AddDbContext\u003CAppDbContext>(options =>\n    options\n        .UseSqlServer(connectionString)\n        .AddInterceptors(new AuditInterceptor(), new SlowQueryInterceptor()));\n```\n\n**Rule of thumb:** Use interceptors for cross-cutting concerns (auditing, logging,\nsoft-delete) that shouldn't pollute entity classes or service code. Prefer\n`SaveChangesInterceptor` over overriding `SaveChanges` directly — it composes cleanly.\n",{"id":82,"difficulty":78,"q":83,"a":84},"ef-unit-of-work-repository","Should you wrap EF Core DbContext in a Repository and Unit of Work pattern?","`DbContext` already implements the **Unit of Work** pattern (change tracker + `SaveChanges`)\nand `DbSet\u003CT>` already acts as a **Repository** (query + add\u002Fremove surface). Wrapping\nthem in another layer duplicates those abstractions. However, a thin repository interface\ncan be justified for testability or for abstracting query logic.\n\n```csharp\n\u002F\u002F Anti-pattern — generic repository that mirrors DbSet exactly:\npublic interface IRepository\u003CT>\n{\n    Task\u003CT?> GetByIdAsync(int id);\n    Task AddAsync(T entity);\n    void Remove(T entity);\n    Task SaveAsync(); \u002F\u002F re-exposes SaveChanges — leaks UoW into the repo\n}\n\u002F\u002F Problem: SaveAsync in each repository breaks the Unit of Work contract.\n\u002F\u002F Two repos saving independently means two transactions.\n\n\u002F\u002F Better — inject DbContext directly in services (simple apps):\npublic class OrderService\n{\n    private readonly AppDbContext _db;\n    public OrderService(AppDbContext db) => _db = db;\n\n    public async Task\u003CList\u003COrder>> GetPendingAsync()\n        => await _db.Orders\n            .AsNoTracking()\n            .Where(o => o.Status == \"Pending\")\n            .ToListAsync();\n}\n\n\u002F\u002F Acceptable thin interface — encapsulates query logic, not UoW:\npublic interface IOrderRepository\n{\n    Task\u003CList\u003COrder>> GetPendingAsync(CancellationToken ct = default);\n    Task\u003COrder?> GetWithItemsAsync(int orderId, CancellationToken ct = default);\n}\n\npublic class EfOrderRepository : IOrderRepository\n{\n    private readonly AppDbContext _db;\n    public EfOrderRepository(AppDbContext db) => _db = db;\n\n    public Task\u003CList\u003COrder>> GetPendingAsync(CancellationToken ct)\n        => _db.Orders.AsNoTracking().Where(o => o.Status == \"Pending\").ToListAsync(ct);\n\n    public Task\u003COrder?> GetWithItemsAsync(int orderId, CancellationToken ct)\n        => _db.Orders.Include(o => o.Items).FirstOrDefaultAsync(o => o.Id == orderId, ct);\n}\n\u002F\u002F SaveChanges remains on the context — owned by the service layer, not the repo.\n```\n\n**Rule of thumb:** Don't create a generic `IRepository\u003CT>` that wraps `DbSet\u003CT>` —\nit adds indirection without benefit. A domain-specific repository interface is fine when\nit encapsulates complex queries. Never expose `SaveChanges` inside a repository method.\n",15,null,{"description":11},"EF Core DbContext interview questions — change tracking, entity states, SaveChanges, lifetime management, DbContext pooling, and interceptors.","dotnet\u002Fentity-framework\u002Fdbcontext-dbset","DbContext & DbSet","Entity Framework Core","entity-framework","2026-06-23","VQ5zE74TIo4nHgSY65q7FMINMkZmGjJajlkcPsfpCjI",[96,97,100,104],{"subtopic":90,"path":21,"order":20},{"subtopic":98,"path":99,"order":12},"Migrations","\u002Fdotnet\u002Fentity-framework\u002Fmigrations",{"subtopic":101,"path":102,"order":103},"Querying","\u002Fdotnet\u002Fentity-framework\u002Fquerying",3,{"subtopic":105,"path":106,"order":107},"Relationships","\u002Fdotnet\u002Fentity-framework\u002Frelationships",4,{"path":109,"title":110},"\u002Fblog\u002Fdotnet-ef-dbcontext-dbset","EF Core DbContext, DbSet, and Change Tracking",1782244118581]