Entity Framework: Advanced Concepts

Welcome to the advanced topics section for Entity Framework. This guide will delve into more complex features and strategies to help you leverage the full power of EF in your .NET applications.

Querying Data Efficiently

Lazy Loading vs. Eager Loading

Understanding how related entities are loaded is crucial for performance. Lazy loading fetches related data only when it's accessed, while eager loading fetches it along with the primary entity. EF Core provides mechanisms for both.


// Eager Loading Example
var customers = _context.Customers
    .Include(c => c.Orders)
        .ThenInclude(o => o.OrderItems)
    .ToList();
            

Projections and Select

Instead of retrieving entire entities, use projections to select only the specific data you need. This significantly reduces the amount of data transferred from the database and improves performance.


var customerOrderSummaries = _context.Customers
    .Select(c => new {
        CustomerName = c.Name,
        OrderCount = c.Orders.Count(),
        LastOrderDate = c.Orders.OrderByDescending(o => o.OrderDate).FirstOrDefault().OrderDate
    })
    .ToList();
            

Change Tracking and Concurrency

Advanced Change Tracking

EF Core's change tracker is a powerful feature that monitors changes to entities. You can manually control its behavior, detach entities, or attach existing ones.

Concurrency Control

Handling concurrent updates from multiple users or processes is vital. EF Core supports optimistic concurrency using row versioning or timestamp columns.

Note: Implement a timestamp or row version column in your database tables and mark the corresponding property in your entity with the [Timestamp] attribute (for EF Core) or IsRowVersion() configuration.

// Example of configuring concurrency token
modelBuilder.Entity<Product>()
    .Property<byte[]>("Timestamp")
    .IsRowVersion();
            

Working with Raw SQL and Stored Procedures

Executing Raw SQL Queries

Sometimes, you might need to execute raw SQL queries for performance optimizations or complex operations not easily expressible in LINQ.


var products = _context.Products.FromSqlRaw("SELECT * FROM Products WHERE Category = {0}", "Electronics");
            

Calling Stored Procedures

EF Core allows you to call stored procedures and map their results to your entities or DTOs.


var customerOrders = _context.CustomerOrders.FromSqlInterpolated($"EXEC GetCustomerOrders {customerId}");
            

Performance Tuning Strategies

Batching Operations

For scenarios involving many inserts, updates, or deletes, consider using batching to reduce the number of round trips to the database.

Connection Resiliency and Retry Logic

Implement strategies to handle transient database connection failures gracefully.

Caching Strategies

For frequently accessed read-only data, integrate caching solutions (e.g., Redis, MemoryCache) to further improve performance.

Advanced Mapping Scenarios

Table-Per-Type (TPT) and Table-Per-Hierarchy (TPH)

Explore different inheritance mapping strategies for your domain models.

Value Objects and Owned Entities

Learn how to model complex types that don't have their own identity and are owned by another entity.

Complex Types and Shadow Properties

Understand how to map complex data structures and use shadow properties for properties that are not explicitly defined on your entity classes.

Extending Entity Framework

Custom Conventions

Define custom conventions to automate the configuration of your model.

Custom Value Converters

Map custom .NET types to database types.

Tip: Always profile your database queries and application performance to identify bottlenecks. Use EF Core's logging features to inspect the generated SQL.