Advanced Topics
This section covers advanced features and techniques for Entity Framework Core (EF Core), enabling you to optimize performance, handle complex scenarios, and customize EF Core's behavior.
1. Raw SQL Queries
Sometimes, you may need to execute raw SQL queries directly against the database. EF Core provides methods to achieve this, offering maximum flexibility.
var users = context.Users.FromSqlRaw("SELECT * FROM Users WHERE Active = 1");
using (var command = context.Database.GetDbConnection().CreateCommand())
{
command.CommandText = "SELECT COUNT(*) FROM Orders";
context.Database.OpenConnection();
var count = command.ExecuteScalar();
}
2. Database-Generated Values
EF Core supports various database-generated values, including sequences, identity columns, and computed columns. Understanding how to configure these is crucial for data integrity.
- Identity Columns: Typically used for primary keys.
- Sequences: A database object that generates unique numbers.
- Computed Columns: Values computed by the database based on other columns.
Configuration can be done using data annotations or the Fluent API.
modelBuilder.Entity<Product>()
.Property(p => p.UniqueCode)
.HasDefaultValueSql("NEWID()");
3. Global Query Filters
Global query filters are applied to all queries for a specific entity type. This is commonly used for implementing soft-delete patterns or tenant isolation.
public class MyDbContext : DbContext
{
public DbSet<Product> Products { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>().HasQueryFilter(p => !p.IsDeleted);
}
}
4. Interceptors
Interceptors allow you to intercept and modify EF Core's behavior, such as logging SQL commands, modifying parameters, or handling exceptions. You can implement interfaces like IDbCommandInterceptor
or IDbConnectionInterceptor
.
5. Change Tracking Proxies
By default, EF Core uses proxies to enable change tracking. You can disable proxy creation if it's not needed, which can improve performance in some scenarios.
optionsBuilder.UseLazyLoadingProxies(false);
6. Concurrency Control
EF Core supports optimistic concurrency control using row versioning (e.g., a timestamp column) or by checking all columns during updates.
modelBuilder.Entity<Blog>()
.Property(b => b.RowVersion)
.IsConcurrencyToken();
DbUpdateConcurrencyException
. You'll need to handle this exception to resolve the conflict.
7. TPT and TPC Inheritance Mapping
EF Core supports different strategies for mapping table-per-type (TPT) and table-per-hierarchy (TPC) inheritance in the database.
- TPT: Each concrete entity type is mapped to its own table.
- TPC: All entity types in a hierarchy are mapped to a single table, with discriminator columns.
These strategies have implications for query performance and database schema complexity.
8. Batch Operations
While EF Core doesn't natively support batching of multiple statements into a single database roundtrip for *all* operations, there are community-driven solutions and techniques to achieve this for significant performance gains, especially for large inserts or updates.
9. Value Objects
Value objects are entities that don't have an identity of their own but are defined by their attributes. EF Core allows you to map value objects by owning them within other entities.
public class Address
{
public string Street { get; set; }
public string City { get; set; }
}
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public Address ShippingAddress { get; set; }
}
When mapping Value Objects, you can choose to map them as owned types, either in the same table as the owner or in separate tables.