Entity Framework Core para .NET Senior
📋 Tópicos Essenciais
1. Configuração e Setup
DbContext Configuration
csharp
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.Email).IsRequired().HasMaxLength(100);
entity.HasIndex(e => e.Email).IsUnique();
});
}
}Dependency Injection
csharp
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
}
}2. Model Configuration
Fluent API
csharp
public class UserConfiguration : IEntityTypeConfiguration<User>
{
public void Configure(EntityTypeBuilder<User> builder)
{
builder.ToTable("Users");
builder.HasKey(u => u.Id);
builder.Property(u => u.Email).IsRequired().HasMaxLength(100);
builder.HasIndex(u => u.Email).IsUnique();
builder.Property(u => u.CreatedAt).HasDefaultValueSql("GETDATE()");
}
}Relationships
csharp
public class OrderConfiguration : IEntityTypeConfiguration<Order>
{
public void Configure(EntityTypeBuilder<Order> builder)
{
builder.HasOne(o => o.Customer)
.WithMany(c => c.Orders)
.HasForeignKey(o => o.CustomerId)
.OnDelete(DeleteBehavior.Restrict);
builder.HasMany(o => o.OrderItems)
.WithOne(oi => oi.Order)
.HasForeignKey(oi => oi.OrderId);
}
}3. Query Performance
Eager Loading
csharp
var users = await context.Users
.Include(u => u.Orders)
.ThenInclude(o => o.OrderItems)
.Include(u => u.Profile)
.ToListAsync();Explicit Loading
csharp
var user = await context.Users.FindAsync(1);
await context.Entry(user)
.Collection(u => u.Orders)
.LoadAsync();Projection
csharp
var userDtos = await context.Users
.Select(u => new UserDto
{
Id = u.Id,
Name = u.Name,
Email = u.Email,
OrderCount = u.Orders.Count
})
.ToListAsync();4. Advanced Querying
Raw SQL
csharp
var users = await context.Users
.FromSqlRaw("SELECT * FROM Users WHERE CreatedAt >= {0}", startDate)
.ToListAsync();Stored Procedures
csharp
var users = await context.Users
.FromSqlRaw("EXEC GetUsersByDate {0}", startDate)
.ToListAsync();Complex Queries
csharp
var result = await context.Orders
.Where(o => o.CreatedAt >= startDate)
.GroupBy(o => new { o.CustomerId, o.Status })
.Select(g => new
{
CustomerId = g.Key.CustomerId,
Status = g.Key.Status,
TotalAmount = g.Sum(o => o.TotalAmount),
OrderCount = g.Count()
})
.ToListAsync();5. Change Tracking
Attach vs Add
csharp
// Para entidades existentes
context.Attach(user);
context.Entry(user).State = EntityState.Modified;
// Para novas entidades
context.Add(user);Change Tracking Optimization
csharp
public async Task UpdateUserAsync(User user)
{
var existingUser = await context.Users.FindAsync(user.Id);
if (existingUser != null)
{
context.Entry(existingUser).CurrentValues.SetValues(user);
await context.SaveChangesAsync();
}
}6. Bulk Operations
Bulk Insert
csharp
public async Task BulkInsertUsersAsync(IEnumerable<User> users)
{
await context.BulkInsertAsync(users.ToList());
}Bulk Update
csharp
public async Task BulkUpdateUsersAsync(IEnumerable<User> users)
{
await context.BulkUpdateAsync(users.ToList());
}7. Migrations
Creating Migrations
bash
dotnet ef migrations add InitialCreate
dotnet ef migrations add AddUserTable
dotnet ef migrations add AddOrderRelationshipsApplying Migrations
bash
dotnet ef database update
dotnet ef database update --target MigrationNameMigration Scripts
bash
dotnet ef migrations script
dotnet ef migrations script --from InitialCreate --to AddUserTable8. Performance Optimization
Query Optimization
csharp
// Use AsNoTracking for read-only queries
var users = await context.Users
.AsNoTracking()
.ToListAsync();
// Use compiled queries for frequently used queries
private static readonly Func<ApplicationDbContext, int, Task<User>> GetUserById =
EF.CompileAsyncQuery((ApplicationDbContext context, int id) =>
context.Users.FirstOrDefault(u => u.Id == id));Connection Management
csharp
public class UnitOfWork : IUnitOfWork
{
private readonly ApplicationDbContext _context;
public UnitOfWork(ApplicationDbContext context)
{
_context = context;
}
public async Task<int> SaveChangesAsync()
{
return await _context.SaveChangesAsync();
}
public void Dispose()
{
_context?.Dispose();
}
}9. Testing
In-Memory Database
csharp
public class TestDbContext : ApplicationDbContext
{
public TestDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseInMemoryDatabase("TestDb");
}
}
}Repository Testing
csharp
[Test]
public async Task GetByIdAsync_ShouldReturnUser()
{
var options = new DbContextOptionsBuilder<ApplicationDbContext>()
.UseInMemoryDatabase(databaseName: "TestDb")
.Options;
using var context = new ApplicationDbContext(options);
var repository = new UserRepository(context);
var user = new User { Name = "Test User", Email = "test@test.com" };
context.Users.Add(user);
await context.SaveChangesAsync();
var result = await repository.GetByIdAsync(user.Id);
Assert.IsNotNull(result);
Assert.AreEqual(user.Name, result.Name);
}10. Advanced Features
Global Query Filters
csharp
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasQueryFilter(u => !u.IsDeleted);
}Value Conversions
csharp
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.Property(u => u.Status)
.HasConversion(
v => v.ToString(),
v => (UserStatus)Enum.Parse(typeof(UserStatus), v));
}Shadow Properties
csharp
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.Property<DateTime>("CreatedAt")
.HasDefaultValueSql("GETDATE()");
}📚 Recursos Adicionais
Livros Recomendados
- "Entity Framework Core in Action" - Jon P Smith
- "Programming Entity Framework" - Julia Lerman
Artigos e Blogs
- Microsoft EF Core Documentation
- Jon P Smith's Blog
- Entity Framework Core GitHub Repository
⚠️ Pontos de Atenção
- N+1 Query Problem: Use Include() adequadamente
- Memory Usage: Use AsNoTracking() para queries somente leitura
- Connection Pooling: Configure adequadamente
- Migration Strategy: Planeje migrations em produção
- Performance: Monitore queries lentas