
Entity Framework6
- 19 installs
- 466 repo stars
- Updated July 25, 2026
- managedcode/dotnet-skills
Helps with ai & agent building tasks.
About
entity-framework6 is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- entity-framework6
- AI & Agent Building
- AI-coding skill
Entity Framework6 by the numbers
- 19 all-time installs (skills.sh)
- +1 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #10,571 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/managedcode/dotnet-skills --skill entity-framework6Add your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 19 |
|---|---|
| repo stars | ★ 466 |
| Last updated | July 25, 2026 |
| Repository | managedcode/dotnet-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
Entity Framework 6
Trigger On
- working in an EF6 codebase on .NET Framework or modern .NET
- deciding whether to keep EF6, move to modern .NET runtime, or port to EF Core
- reviewing EDMX, code-first, or legacy ASP.NET/WPF/WinForms data access
- planning a data layer migration strategy
Workflow
1. Audit current EF6 usage before planning any migration. Identify which features the codebase depends on:
// Common EF6-specific patterns to inventory:
// - EDMX designer models (check for *.edmx files)
// - ObjectContext vs DbContext usage
// - Lazy loading with virtual navigation properties
// - Database.SqlQuery<T>() for raw SQL
// - Stored procedure mappings in model
// - Spatial types (DbGeography, DbGeometry)2. Decide runtime vs ORM migration separately:
| Path | When to use |
|---|---|
| Keep EF6 on .NET Framework | Legacy app with no runtime pressure |
| EF6 on modern .NET | Runtime upgrade needed, ORM migration too risky |
| EF6 → EF Core | Clean data layer, no EDMX, minimal stored-procedure mapping |
3. For maintenance work — keep EF6 stable:
- use repository + unit of work patterns to isolate data access (see references/patterns.md)
- prefer
DbContextoverObjectContextfor new code - use
AsNoTracking()for read-only queries - configure concurrency tokens with
[ConcurrencyCheck]orIsRowVersion()
4. For migration work — validate each slice:
- map EF6 features to EF Core equivalents (see references/migration.md)
- migrate one bounded context at a time, not the entire data layer
- run integration tests against the real database provider, not InMemory
- verify:
dotnet ef migrations addsucceeds, queries produce equivalent results, lazy loading behavior matches expectations
5. Do not promise EF Core features to EF6 codebases — EF6 is stable and supported but not on the innovation path. Keep expectations realistic.
Current Upstream Notes
- The current EF Core vs EF6 comparison page keeps the migration decision separate from runtime modernization. EF6 can remain the right ORM when EDMX, ObjectContext, or complex legacy mappings dominate the risk.
- EF Core
v9.0.17servicing does not change EF6 guidance by itself; only move an EF6 codebase when the project has a bounded migration slice and database-backed equivalence tests.
flowchart LR
A["Audit EF6 usage"] --> B{"EDMX or complex mappings?"}
B -->|Yes| C["High migration cost — consider keeping EF6"]
B -->|No| D["Evaluate EF Core migration"]
D --> E["Migrate one context at a time"]
E --> F["Integration test against real DB"]
C --> G["Modernize runtime only"]
F --> H["Validate query equivalence"]
G --> HDeliver
- realistic EF6 maintenance or migration guidance based on actual codebase audit
- clear separation between runtime upgrade and ORM upgrade work
- bounded migration slices with concrete validation checkpoints
- reduced risk for legacy data access changes
Validate
- EF6 feature inventory is complete before migration planning starts
- migration assumptions are backed by real feature usage, not guesses
- EF6-only features (EDMX, spatial types, ObjectContext patterns) are identified early
- integration tests run against the real database provider, not mocks or InMemory
- the proposed path avoids unnecessary churn in stable data access code
References
- references/migration.md - decision framework, migration approaches, EF6-to-EF Core feature mapping, and common pitfalls
- references/patterns.md - repository and unit of work patterns, query optimization, concurrency handling, auditing, and testing strategies for EF6 codebases
{
"version": "1.0.2",
"category": "Data",
"package_prefix": "EntityFramework"
}
EF6 to EF Core Migration Guide
Migration Decision Framework
When to Stay on EF6
- Application is stable and not actively evolving
- Heavy use of EDMX designer models without code-first equivalents
- Complex stored procedure mappings that drive business logic
- Dependency on ObjectContext or ObjectStateManager APIs
- No plans to move the host application to modern .NET
When to Consider EF Core
- Targeting .NET 6+ or planning a runtime migration
- Need for cross-platform deployment (Linux, containers)
- Desire for improved performance characteristics
- Need for features only available in EF Core (e.g., compiled queries, split queries, interceptors)
- Starting a new module or service that will coexist with EF6 code
When to Skip EF Core Entirely
- Moving to a different data access strategy (Dapper, raw ADO.NET, document stores)
- Decomposing the monolith into microservices with dedicated data strategies
- The data layer is being replaced by an external API or service
Migration Approaches
Parallel Coexistence
Run EF6 and EF Core side by side in the same solution:
1. Add EF Core packages alongside existing EF6 references 2. Create a new DbContext for EF Core targeting the same database 3. Migrate entity configurations incrementally 4. Gradually shift new features and queries to EF Core 5. Retire EF6 DbContext once all code paths are migrated
Benefits:
- No big-bang cutover
- Validate behavior slice by slice
- Rollback is straightforward
Risks:
- Two DbContexts means two change trackers; avoid crossing them in the same unit of work
- Schema migrations need coordination
Module-by-Module Migration
Migrate entire bounded contexts or modules at once:
1. Identify module boundaries in the existing codebase 2. Extract the module's data access into a dedicated project 3. Port that project to EF Core and modern .NET 4. Integrate via API or shared database until full cutover
Benefits:
- Clean separation reduces cross-cutting risks
- Easier to test in isolation
Risks:
- Requires clear module boundaries
- May need temporary integration shims
Big-Bang Rewrite
Replace the entire data layer in a single release:
1. Map all entities, configurations, and queries 2. Port all migrations or regenerate schema 3. Run extensive regression testing 4. Deploy as a single release
Benefits:
- No ongoing dual maintenance
Risks:
- High risk of regressions
- Long development cycle without production feedback
- Rollback is difficult
Feature Mapping
Entity Configuration
| EF6 | EF Core |
|---|---|
EntityTypeConfiguration<T> | IEntityTypeConfiguration<T> or Fluent API |
modelBuilder.Configurations.Add() | modelBuilder.ApplyConfigurationsFromAssembly() |
| EDMX designer | No equivalent; use code-first |
| Complex Types | Owned Types |
Lazy Loading
| EF6 | EF Core |
|---|---|
| Enabled by default with virtual props | Opt-in via UseLazyLoadingProxies() or ILazyLoader |
Change Tracking
| EF6 | EF Core |
|---|---|
| Snapshot by default | Snapshot by default; change-tracking proxies optional |
ObjectStateManager | ChangeTracker |
Stored Procedures
| EF6 | EF Core |
|---|---|
MapToStoredProcedures() for CUD | Sproc mapping for CUD introduced in EF Core 7 |
| Function imports in EDMX | FromSql or raw SQL |
Migrations
| EF6 | EF Core |
|---|---|
Add-Migration, Update-Database | Add-Migration, Update-Database (similar commands) |
__MigrationHistory table | __EFMigrationsHistory table |
Common Pitfalls
Behavioral Differences
- Query translation: EF Core has different LINQ translation behavior; some queries that worked in EF6 may throw or produce different SQL
- Cascade delete defaults: EF Core defaults to cascade delete for required relationships; EF6 does not
- Shadow properties: EF Core tracks FK values as shadow properties by default; EF6 requires explicit FK properties
- Global query filters: EF Core supports them; EF6 does not
Missing Features in EF Core
Some EF6 features have no direct equivalent:
- EDMX designer and visual model-first workflows
- ObjectContext API (only DbContext is supported)
- Automatic migrations (removed; use explicit migrations)
- Entity SQL (ESQL) query language
Provider Differences
- Verify your database provider has EF Core support
- Provider feature parity varies; some advanced database features may differ
- Test against the real database, not just in-memory
Testing Strategy
1. Characterization tests: Before migration, write tests that capture current EF6 behavior 2. SQL diff comparisons: Compare generated SQL between EF6 and EF Core for critical queries 3. Integration tests: Run against a real database with realistic data volumes 4. Performance baselines: Measure query performance before and after migration
References
EF6 Maintenance Patterns
Repository and Unit of Work
Basic Repository Pattern
public interface IRepository<T> where T : class
{
T GetById(int id);
IQueryable<T> Query();
void Add(T entity);
void Update(T entity);
void Delete(T entity);
}
public class EF6Repository<T> : IRepository<T> where T : class
{
private readonly DbContext _context;
private readonly DbSet<T> _dbSet;
public EF6Repository(DbContext context)
{
_context = context;
_dbSet = context.Set<T>();
}
public T GetById(int id) => _dbSet.Find(id);
public IQueryable<T> Query() => _dbSet;
public void Add(T entity) => _dbSet.Add(entity);
public void Update(T entity) => _context.Entry(entity).State = EntityState.Modified;
public void Delete(T entity) => _dbSet.Remove(entity);
}Unit of Work Pattern
public interface IUnitOfWork : IDisposable
{
IRepository<TEntity> Repository<TEntity>() where TEntity : class;
int SaveChanges();
Task<int> SaveChangesAsync();
}
public class EF6UnitOfWork : IUnitOfWork
{
private readonly DbContext _context;
private readonly Dictionary<Type, object> _repositories = new();
public EF6UnitOfWork(DbContext context)
{
_context = context;
}
public IRepository<TEntity> Repository<TEntity>() where TEntity : class
{
if (!_repositories.ContainsKey(typeof(TEntity)))
{
_repositories[typeof(TEntity)] = new EF6Repository<TEntity>(_context);
}
return (IRepository<TEntity>)_repositories[typeof(TEntity)];
}
public int SaveChanges() => _context.SaveChanges();
public Task<int> SaveChangesAsync() => _context.SaveChangesAsync();
public void Dispose() => _context.Dispose();
}Connection and Context Management
Scoped Context Lifetime
Always scope DbContext to a logical unit of work:
// ASP.NET MVC: use per-request lifetime
public class OrderController : Controller
{
private readonly MyDbContext _context;
public OrderController(MyDbContext context)
{
_context = context;
}
}
// Non-web: use explicit using blocks
using (var context = new MyDbContext())
{
var orders = context.Orders.Where(o => o.Status == "Pending").ToList();
// process orders
context.SaveChanges();
}Avoiding Long-Lived Contexts
Do not:
- Keep a DbContext alive across multiple HTTP requests
- Share a DbContext across threads
- Cache a DbContext in a static field
Connection Resiliency
Configure retry logic for transient failures:
public class MyDbConfiguration : DbConfiguration
{
public MyDbConfiguration()
{
SetExecutionStrategy("System.Data.SqlClient",
() => new SqlAzureExecutionStrategy(5, TimeSpan.FromSeconds(10)));
}
}Query Optimization
Eager Loading
Use Include to avoid N+1 queries:
var orders = context.Orders
.Include(o => o.Customer)
.Include(o => o.OrderItems.Select(oi => oi.Product))
.Where(o => o.OrderDate >= startDate)
.ToList();Projection
Select only needed columns:
var orderSummaries = context.Orders
.Where(o => o.Status == "Shipped")
.Select(o => new OrderSummaryDto
{
OrderId = o.Id,
CustomerName = o.Customer.Name,
TotalAmount = o.OrderItems.Sum(oi => oi.Quantity * oi.UnitPrice)
})
.ToList();No-Tracking Queries
Use AsNoTracking() for read-only scenarios:
var products = context.Products
.AsNoTracking()
.Where(p => p.IsActive)
.ToList();Compiled Queries (LINQ to Entities)
For frequently executed queries:
private static readonly Func<MyDbContext, int, Customer> GetCustomerById =
CompiledQuery.Compile<MyDbContext, int, Customer>(
(ctx, id) => ctx.Customers.FirstOrDefault(c => c.Id == id));
// Usage
var customer = GetCustomerById(_context, customerId);Handling Concurrency
Optimistic Concurrency with RowVersion
public class Order
{
public int Id { get; set; }
public string Status { get; set; }
[Timestamp]
public byte[] RowVersion { get; set; }
}
// Handle concurrency conflict
try
{
context.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
var entry = ex.Entries.Single();
var databaseValues = entry.GetDatabaseValues();
if (databaseValues == null)
{
// Entity was deleted
}
else
{
// Resolve conflict: client wins, database wins, or merge
entry.OriginalValues.SetValues(databaseValues);
}
}Auditing and Interception
SaveChanges Override for Auditing
public class AuditableDbContext : DbContext
{
public override int SaveChanges()
{
var entries = ChangeTracker.Entries()
.Where(e => e.Entity is IAuditable &&
(e.State == EntityState.Added || e.State == EntityState.Modified));
foreach (var entry in entries)
{
var auditable = (IAuditable)entry.Entity;
auditable.ModifiedDate = DateTime.UtcNow;
auditable.ModifiedBy = GetCurrentUser();
if (entry.State == EntityState.Added)
{
auditable.CreatedDate = DateTime.UtcNow;
auditable.CreatedBy = GetCurrentUser();
}
}
return base.SaveChanges();
}
}Command Interception for Logging
public class LoggingInterceptor : IDbCommandInterceptor
{
public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> context)
{
LogCommand(command);
}
public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> context)
{
LogCommand(command);
}
public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> context)
{
LogCommand(command);
}
private void LogCommand(DbCommand command)
{
Debug.WriteLine($"SQL: {command.CommandText}");
}
// Implement other interface members...
}
// Registration
DbInterception.Add(new LoggingInterceptor());Stored Procedure Integration
Mapping CUD Operations
modelBuilder.Entity<Order>()
.MapToStoredProcedures(s =>
s.Insert(i => i.HasName("usp_InsertOrder"))
.Update(u => u.HasName("usp_UpdateOrder"))
.Delete(d => d.HasName("usp_DeleteOrder")));Calling Stored Procedures Directly
// Return entities
var orders = context.Database.SqlQuery<Order>(
"EXEC GetOrdersByCustomer @customerId",
new SqlParameter("@customerId", customerId)).ToList();
// Non-query
context.Database.ExecuteSqlCommand(
"EXEC ArchiveOldOrders @cutoffDate",
new SqlParameter("@cutoffDate", cutoffDate));Testing Strategies
Integration Testing with LocalDB
[TestClass]
public class OrderRepositoryTests
{
private MyDbContext _context;
[TestInitialize]
public void Setup()
{
var connectionString = @"Data Source=(LocalDb)\MSSQLLocalDB;Initial Catalog=TestDb;Integrated Security=True";
_context = new MyDbContext(connectionString);
_context.Database.CreateIfNotExists();
}
[TestCleanup]
public void Cleanup()
{
_context.Database.Delete();
_context.Dispose();
}
[TestMethod]
public void CanAddOrder()
{
var order = new Order { Status = "New" };
_context.Orders.Add(order);
_context.SaveChanges();
Assert.IsTrue(order.Id > 0);
}
}Mocking with Interfaces
Wrap DbContext behind an interface for unit testing:
public interface IMyDbContext
{
IDbSet<Order> Orders { get; }
int SaveChanges();
}
// In tests, mock IMyDbContext
var mockContext = new Mock<IMyDbContext>();
var mockOrders = new Mock<IDbSet<Order>>();
mockContext.Setup(c => c.Orders).Returns(mockOrders.Object);Performance Monitoring
Database Logging
context.Database.Log = sql => Debug.WriteLine(sql);Identifying Slow Queries
Use SQL Server Profiler, Extended Events, or Query Store alongside EF6 logging to correlate slow queries with application code paths.
Common Anti-Patterns to Avoid
1. Lazy loading in loops: Causes N+1 queries; use eager loading or projection 2. Tracking entities unnecessarily: Use AsNoTracking() for read-only queries 3. Returning IQueryable from repositories: Leaks query composition outside the data layer 4. Ignoring connection management: Always dispose DbContext properly 5. Mixing ObjectContext and DbContext: Pick one API and stick with it 6. Skipping concurrency handling: Add RowVersion for entities with concurrent updates