Database and ORM Enhancements in .NET 9
David Shergilashvili
?? Engineering Leadership | Enterprise Solutions Architect | Technical Visionary | Architecting Scalable & Innovative Digital Solutions
Data access remains critical to modern applications, and .NET 9 introduces significant improvements to Entity Framework Core and general database interactions. These enhancements make database operations more efficient while providing developers powerful tools for managing data relationships and queries.
Enhanced Query Performance
Entity Framework Core in .NET 9 brings remarkable improvements to query performance through smarter query compilation and execution. Let's explore these improvements through practical examples:
public class OptimizedDataAccess
{
private readonly ApplicationDbContext _context;
private readonly ILogger<OptimizedDataAccess> _logger;
public OptimizedDataAccess(
ApplicationDbContext context,
ILogger<OptimizedDataAccess> logger)
{
_context = context;
_logger = logger;
}
public async Task<IEnumerable<OrderSummary>> GetOrderSummariesAsync(
DateTime startDate,
DateTime endDate)
{
// New in .NET 9: Optimized query compilation
var query = _context.Orders
.AsNoTracking() // More efficient for read-only data
.Where(o => o.OrderDate >= startDate && o.OrderDate <= endDate)
.GroupBy(o => new
{
o.CustomerId,
Month = o.OrderDate.Month,
Year = o.OrderDate.Year
})
.Select(g => new OrderSummary
{
CustomerId = g.Key.CustomerId,
Period = new DateTime(g.Key.Year, g.Key.Month, 1),
TotalOrders = g.Count(),
TotalAmount = g.Sum(o => o.Amount),
AverageOrderValue = g.Average(o => o.Amount)
});
// New in .NET 9: Enhanced query execution statistics
var result = await query.TagWith("GetOrderSummaries")
.WithStatistics(stats =>
{
_logger.LogInformation(
"Query execution time: {Time}ms, " +
"Rows affected: {Rows}",
stats.ExecutionTime.TotalMilliseconds,
stats.RowsAffected
);
})
.ToListAsync();
return result;
}
}
Improved Relationship Management
.NET 9 introduces better ways to handle entity relationships and navigation properties:
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
// New in .NET 9: Lazy loading with value tasks
public ValueTask<ICollection<Order>> OrdersAsync { get; set; }
// New in .NET 9: Enhanced many-to-many relationship handling
public ICollection<Product> FavoriteProducts { get; set; }
}
public class ApplicationDbContext : DbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// New in .NET 9: Fluent configuration for relationships
modelBuilder.Entity<Customer>()
.HasMany(c => c.FavoriteProducts)
.WithMany()
.UsingEntity<Dictionary<string, object>>(
"CustomerFavoriteProducts",
j => j.HasOne<Product>()
.WithMany()
.OnDelete(DeleteBehavior.Restrict),
j => j.HasOne<Customer>()
.WithMany()
.OnDelete(DeleteBehavior.Cascade)
);
// New in .NET 9: Better support for complex types
modelBuilder.Entity<Order>()
.OwnsOne(o => o.ShippingAddress, sa =>
{
sa.WithOwner();
sa.UsePropertyAccessMode(
PropertyAccessMode.PreferFieldDuringConstruction
);
});
}
}
Advanced Query Capabilities
The query system in EF Core .NET 9 provides more sophisticated options for data retrieval:
领英推荐
public class AdvancedQueryManager
{
private readonly ApplicationDbContext _context;
public async Task<IEnumerable<ProductAnalytics>> AnalyzeProductsAsync(
AnalyticsOptions options)
{
// New in .NET 9: Enhanced SQL generation
var query = _context.Products
.Include(p => p.Categories)
.Include(p => p.Reviews.Where(r => r.Rating >= 4))
.AsSplitQuery() // Better handling of complex queries
.Where(p => p.IsActive);
// New in .NET 9: Dynamic query composition
if (options.IncludeSales)
{
query = query.Include(p => p.Sales
.Where(s => s.Date >= options.StartDate)
.OrderByDescending(s => s.Amount)
);
}
// New in .NET 9: Improved aggregation
return await query
.Select(p => new ProductAnalytics
{
ProductId = p.Id,
Name = p.Name,
CategoryCount = p.Categories.Count(),
AverageRating = p.Reviews.Average(r => r.Rating),
TotalSales = p.Sales.Sum(s => s.Amount),
TopCategories = p.Categories
.OrderByDescending(c => c.Products.Count)
.Take(3)
.Select(c => c.Name)
.ToList()
})
.TagWith("ProductAnalytics") // Better query identification
.AsSingleQuery() // Optimization hint
.ToListAsync();
}
}
Batch Operations and Performance
.NET 9 enhances support for batch operations and provides better performance monitoring:
public class BatchProcessor
{
private readonly ApplicationDbContext _context;
private readonly ILogger<BatchProcessor> _logger;
public async Task ProcessBatchUpdatesAsync(
IEnumerable<OrderUpdate> updates)
{
// New in .NET 9: Enhanced batch operations
await _context.Orders
.Where(o => updates.Select(u => u.OrderId).Contains(o.Id))
.ExecuteUpdateAsync(setters => setters
.SetProperty(o => o.Status, o => OrderStatus.Updated)
.SetProperty(o => o.ModifiedDate, DateTime.UtcNow)
);
// New in .NET 9: Better transaction handling
using var transaction = await _context.Database
.BeginTransactionAsync(IsolationLevel.ReadCommitted);
try
{
foreach (var batch in updates.Chunk(100))
{
// Process updates in batches
await ProcessUpdateBatchAsync(batch);
// New in .NET 9: Transaction savepoints
await transaction.CreateSavepointAsync(
$"Batch_{Guid.NewGuid()}"
);
}
await transaction.CommitAsync();
}
catch (Exception ex)
{
await transaction.RollbackAsync();
_logger.LogError(ex, "Failed to process batch updates");
throw;
}
}
}
Migration and Schema Management
.NET 9 provides improved tools for managing database schemas and migrations:
public class SchemaManager
{
private readonly ApplicationDbContext _context;
public async Task<SchemaValidationResult> ValidateSchemaAsync()
{
// New in .NET 9: Enhanced schema validation
var validator = new SchemaValidator(_context);
return await validator.ValidateAsync(options =>
{
options.ValidateIndexes = true;
options.ValidateConstraints = true;
options.ValidateForeignKeys = true;
options.GenerateReport = true;
});
}
public async Task ApplyMigrationsAsync()
{
// New in .NET 9: Better migration handling
var migrator = _context.Database.GetMigrator();
// Get pending migrations
var pending = await migrator.GetPendingMigrationsAsync();
foreach (var migration in pending)
{
// New in .NET 9: Migration checkpoints
await migrator.CreateCheckpointAsync(migration);
try
{
await migrator.MigrateAsync(migration);
// Verify migration success
await ValidateMigrationAsync(migration);
}
catch (Exception ex)
{
// Rollback to last checkpoint
await migrator.RollbackToCheckpointAsync(migration);
throw;
}
}
}
}
Conclusion
The database and ORM improvements in .NET 9 significantly advance how we interact with data in our applications. From enhanced query performance to better relationship management and improved batch operations, these features provide developers with powerful tools for building efficient and maintainable data access layers. By understanding and utilizing these improvements effectively, developers can create applications that handle data more efficiently while maintaining code quality and performance.