![Entity Framework Core]()
Entity Framework (EF) is the most popular object-relational mapper (ORM) for .NET developers. It provides an abstraction over database access and improves developer productivity. With the release of .NET 9, EF continues to evolve, offering new features and performance improvements. However, to fully leverage its capabilities, developers must follow best practices and optimize their code for performance.
In this article, we’ll explore the best practices for using Entity Framework in .NET 9 and share tips to improve performance.
1. Use AsNoTracking for Read-Only Queries
By default, EF tracks changes to entities, which can be unnecessary for read-only queries. Using AsNoTracking() improves performance by reducing memory usage and tracking overhead.
var customers = dbContext.Customers.AsNoTracking().ToList();
2. Leverage Eager Loading Wisely
Choose explicit eager loading with include to get related data in one go, avoiding the N+1 query problem. +1 query issue. Lazy loading can introduce performance overhead if not managed properly.
var users = await _context.Users.Include(u => u.Posts).ToListAsync();
3. Use Projections to Retrieve Only Necessary Data
Instead of loading full entity graphs, use Select to project only the data you need into DTOs or anonymous types.
var customers = dbContext.Customers
.Select(c => new { c.Id, c.Name, c.Email })
.ToList();
4. Use Compiled Queries for Repeated Queries
.NET 9 enhances compiled queries, which can significantly improve performance by caching execution plans. Compiled queries can significantly improve performance for frequently executed queries by pre-compiling them. Use EF.CompileQuery to define reusable queries.
private static readonly Func<MyDbContext, int, Customer?> GetCustomerById =
EF.CompileQuery((MyDbContext context, int id) =>
context.Customers.FirstOrDefault(c => c.Id == id));
var customer = GetCustomerById(dbContext, 1);
5. Use Indexes for Faster Query Execution
Ensure database indexes are created for frequently queried columns. Poorly indexed tables can lead to slow query performance, even if your EF code is optimized.
[Index(nameof(Email), IsUnique = true)]
public class Customer {
public int Id { get; set; }
public string Email { get; set; }
}
6. Enable Lazy Loading with Caution
Lazy loading can cause unintended multiple queries. Prefer explicit loading for better control.
var customer = context.Customers.Find(1);
context.Entry(customer).Collection(c => c.Orders).Load();
7. Use Connection Pooling for Performance Optimization
.NET 9 improves connection pooling, reducing overhead for database connections. Ensure connection pooling is enabled in your database provider settings.
When configuring EF Core with SQL Server, ensure connection pooling is optimized via MinPoolSize and MaxPoolSize settings in the connection string:
var optionsBuilder = new DbContextOptionsBuilder<AppDbContext>();
optionsBuilder.UseSqlServer("Server=myServer;Database=myDB;User Id=myUser;Password=myPass;Min Pool Size=5;Max Pool Size=100;");
8. Use Asynchronous Programming
Leverage asynchronous methods like ToListAsync(), FirstOrDefaultAsync(), and SaveChangesAsync() to improve the scalability of your application by freeing up threads while waiting for database operations.
var products = await context.Products.ToListAsync();
9. Use Connection Resiliency
Enable connection resiliency to handle transient database errors gracefully. EF Core 9 provides built-in support for retrying failed database operations.
optionsBuilder.UseSqlServer(
connectionString,
options => options.EnableRetryOnFailure());
10. Batch Updates and Deletes
EF Core 9 introduces improved support for batch updates and deletes. Instead of executing individual update/delete statements, use ExecuteUpdate and ExecuteDelete to perform bulk operations efficiently.
context.Products
.Where(p => p.Price < 10)
.ExecuteUpdate(p => p.SetProperty(x => x.Price, x => x.Price * 1.1));
Additional tips to improve the performance with Entity Framework
Use Transactions for Multiple Database Changes
EF Core supports transactions to ensure data consistency and performance:
using var transaction = context.Database.BeginTransaction();
try {
context.Orders.Add(new Order { ... });
context.SaveChanges();
transaction.Commit();
} catch {
transaction.Rollback();
}
Optimize Large Queries with Pagination
Avoid retrieving excessive records by implementing pagination:
var pageSize = 10;
var pageNumber = 2;
var paginatedOrders = context.Orders.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList();
Use Stored Procedures for Complex Queries
Stored procedures can outperform ORM-based queries for complex operations:
var customers = context.Customers.FromSqlRaw("EXEC GetActiveCustomers").ToList();
Disable Change Tracking for Performance-Intensive Queries
For large queries where updates are not needed, disable change tracking:
context.ChangeTracker.AutoDetectChangesEnabled = false;
Reduce Database Round-Trips with Bulk Inserts and Updates
For bulk data modifications, use EFCore.BulkExtensions:
await context.BulkInsertAsync(customers);
await context.BulkUpdateAsync(customers);
Profile and Tune Queries Using Database Tools
Use database profiling tools like SQL Server Profiler, PostgreSQL EXPLAIN ANALYZE, or MySQL EXPLAIN to identify slow queries and optimize indexes.
Use JSON Columns for Storing Non-Relational Data
For flexible, schema-less data storage, leverage JSON columns in databases like PostgreSQL and SQL Server.
public class Product {
public int Id { get; set; }
public string Name { get; set; }
public string SpecsJson { get; set; } // Store JSON data
}
Upgrade to the Latest EF Core Version
Stay updated with the latest EF Core versions in .NET 9 to take advantage of performance improvements and security fixes.
Avoid Overusing AutoMapper
While AutoMapper is a convenient tool for mapping entities to DTOs, overusing it can lead to performance issues. Consider manual mapping for critical performance paths.
Final Thoughts
Entity Framework is a versatile and powerful ORM, but its performance depends on how it’s used. By following these best practices and leveraging the new features in .NET 9, you can build high-performance applications that scale efficiently. Always monitor your application’s performance, optimize your queries, and stay updated with the latest EF Core improvements to ensure your application runs smoothly.