Front Matter
- Preface
- Introduction
- About the Author
Part I — Intermediate Core Concepts
- Setting the Stage with EF Core 10 and PostgreSQL 18
- What EF Core 10 shipped
- What PostgreSQL 18 means for your EF Core code
- Npgsql: the driver, the provider, and one version rule
- Meet LuminaWork
- The book environment: one container, one volume, one port
- Project setup: the toolchain, the pins, the connection
- First connection, and how this book runs
- Summary
- Key Terms
- Practice Exercises
- What's Next
- Advanced DbContext and Model Configuration
- Six contexts, one database
- The life of a context
- Three ways to configure one model
- Conventions at scale
- One entity, one configuration class
- Shadow properties and backing fields
- Value converters — and the comparers they owe you
- The milestone: a model ready to become a schema
- Summary
- Key Terms
- Practice Exercises
- What's Next
- PostgreSQL Mapping Strategies
- Naming: what the convention promised, the DDL delivers
- The core entities on the page
- A working tour of PostgreSQL's column types
- Value generation: the decision matrix
- Generated columns: virtual by default, stored by choice
- Owned entities, complex types, and table splitting
- The milestone: two migrations and a live schema
- Summary
- Key Terms
- Practice Exercises
- What's Next
- Relationships and Inheritance
- One-to-many, done right
- Many-to-many: name the join
- One-to-one and the module boundary
- Cascade behavior: two rulebooks, one graph
- Inheritance mapping: TPH, TPT, TPC
- Choosing TPH for task kinds
- Owned types, JSONB, or a table of its own
- The milestone: the graph goes live
- Summary
- Key Terms
- Practice Exercises
- What's Next
- Migrations and Schema Management
- Inside a scaffolded migration
- When the differ runs out of vocabulary
- The migration EF cannot write for you
- Scripts, bundles, and the machine that has no source tree
- EF Core 10's per-migration transaction
- Seeding: three answers, and the one this book runs
- Zero downtime: expand, then contract
- The milestone: the pipeline, end to end
- Summary
- Key Terms
- Practice Exercises
- What's Next
Part II — Querying and Performance
- Advanced LINQ Translation
- What happens between your LINQ and PostgreSQL
- The ritual, and the operator that finally retires it
- Where joins come from, and what grouping becomes
- One runtime list, three translations
- The translations you only get on PostgreSQL
- Where the query stops being SQL
- The milestone: the whole feed, translated
- Summary
- Key Terms
- Practice Exercises
- What's Next
- Performance Tuning with PostgreSQL 18
- The lab bench: a million rows and a fixed floor
- Reading an execution plan
- Indexes answer questions
- Smaller, denser, smarter
- Beyond B-tree: GIN, GiST and BRIN
- Skip scans, and what they are not
- Asynchronous I/O, and why sequential scans changed
- Partitions at volume, and the index that summarizes storage
- Naming your queries before you need to
- Cancellation, and the retry that changes what a transaction means
- The index pass, measured
- Summary
- Key Terms
- Practice Exercises
- What's Next
- Efficient Loading Patterns
- Three ways to ask for related data
- One query, or several
- Narrow the question instead
- Pagination, and the cliff at page ten thousand
- Keyset pagination: ask for the next page, not the nth
- Offset against keyset, measured
- Summary
- Key Terms
- Practice Exercises
- What's Next
- Advanced Query Techniques
- Four ways out, and where each one lands
- Raw SQL, safely
- Calling PostgreSQL's own functions
- Two filters, two names, one entity
- Compiled queries, and the caches around them
- Summary
- Key Terms
- Practice Exercises
- What's Next
- Bulk Operations and Concurrency
- One statement instead of forty thousand
- What the statement gives back
- The update that vanished
- Transactions you decide about
- Deadlocks, and what is safe to retry
- Summary
- Key Terms
- Practice Exercises
- What's Next
Part III — PostgreSQL Superpowers
- JSON and Semi-Structured Data
- The fields you did not design
- Three routes into one column
- Reaching inside from LINQ
- Making it fast: GIN over a document
- Document, complex type, or columns
- Reading it back out
- Summary
- Key Terms
- Practice Exercises
- What's Next
- Full-Text Search and Advanced Text
- The full-text model
- Designing search.search_document
- Full-text search from LINQ
- When the words are wrong: pg_trgm
- citext, ILIKE, and unaccent
- Where lexical search stops being enough
- Summary
- Key Terms
- Practice Exercises
- What's Next
- Arrays, Ranges, and Specialized Types
- The tags column, finally explained
- Querying arrays: three questions, two operators, one index
- Ranges: a time window is one value
- FieldOps is born: one migration, one theorem
- Native enums, and what they cost
- Composite types and domains
- Summary
- Key Terms
- Practice Exercises
- What's Next
- Geospatial Data with PostGIS
- PostGIS and the NetTopologySuite plugin
- Geometry versus geography
- The migration, and the backfill it owes
- Proximity and containment, from LINQ
- The spatial index: GiST, second time in anger
- The milestone: tasks near me
- Summary
- Key Terms
- Practice Exercises
- What's Next
- Vector Search and Embeddings with pgvector
- From matching words to measuring meaning
- The plugin, the column, and the migration that was already applied
- Where the vectors come from
- Distance functions, from LINQ
- The HNSW index, and recall you must measure
- Hybrid search: fusing words and meaning
- Where this book stops
- Summary
- Key Terms
- Practice Exercises
- What's Next
Part IV — Production Architecture and Operations
- Interceptors, Diagnostics, and Logging
- The interception surface
- Command interceptors: the slow-query log you own
- Connection interceptors: identity at the moment of opening
- Transaction and SaveChanges interceptors
- Diagnostic listeners: observation without registration
- Structured logging: Serilog, categories, and the redacted line
- OpenTelemetry: spans and meters
- The milestone: one composition root, two profiles
- Summary
- Key Terms
- Practice Exercises
- What's Next
- Temporal Data and Auditing
- Two kinds of time
- Application time in the schema: PostgreSQL 18's temporal constraints
- The audit trail: giving the skeleton a table
- Entity history and point-in-time reads
- Soft delete, completed
- The set-based gap: auditing what the tracker never sees
- Row versioning — and why xmin is not history
- Practical system-versioned data: the decision framework
- Summary
- Key Terms
- Practice Exercises
- What's Next
- Multi-Tenancy and Security
- Three ways to keep tenants apart
- Layer one: named query filters, and where they stop
- Resolving the tenant: requests, jobs, and the connection
- Layer two: row-level security
- Defense in depth is a testable claim
- Direct access without shared passwords: PostgreSQL 18's OAuth
- Operating shared tables: migrations, exports, erasure
- Summary
- Key Terms
- Practice Exercises
- What's Next
- Testing and Integration Testing
- What the in-memory provider is actually testing
- A real PostgreSQL, started by the test run
- Migrate, seed, and the reset that makes it affordable
- The suite as a tour of the book
- Testing the migrations themselves
- Proving resilience: an execution strategy under a dropped connection
- What runs on every push
- Summary
- Key Terms
- Practice Exercises
- What's Next
- Deployment, CI/CD, and DevOps
- What a release actually is
- Two images, and the one that must not carry a compiler
- Kubernetes, and the ranking nobody enjoys hearing
- Who runs the migrations, and when
- Two pools, and the line where your session stops being yours
- Retry, and the decision the last chapter left you
- The I/O knobs, and the column that says what changing one costs
- Watching from the server side, and knowing the pod is alive
- Backups, and the rehearsal that makes them real
- Summary
- Key Terms
- Practice Exercises
- What's Next
- Microservices and Event-Driven Patterns
- Six schemas, six services waiting
- The dual write, and the table that fixes it
- The dispatcher, and the query that makes it safe to run twice
- Waking the dispatcher without polling
- An event store on jsonb, and the projection it feeds
- Change data capture, and the setting that has been waiting since Chapter 1
- Choosing between them
- What you now operate
- Summary
- Key Terms
- Practice Exercises
- What's Next
Appendices
- Appendix A — Npgsql Provider Reference for EF Core 10
- Appendix B — PostgreSQL 18 SQL Features Quick Reference
- Appendix C — EF Core 10 API Changes and Migration Guide
- Appendix D — SQL Server to PostgreSQL Translation Guide
- Appendix E — LuminaWork Architecture and Repository Guide
- Other Books You’ll Enjoy
- Keyword Index
