Agent skill
abp-ef-core
ABP Entity Framework Core - DbContext, entity configuration, EfCoreRepository implementation, migrations (dotnet ef migrations add), data seeding. Use when working in EntityFrameworkCore projects, adding migrations, or implementing EF Core repositories.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/abp-ef-core
SKILL.md
ABP Entity Framework Core
Docs: https://abp.io/docs/latest/framework/data/entity-framework-core
Never Do
| Don't | Do Instead |
|---|---|
Skip b.ConfigureByConvention() |
Always call it first in entity config |
AddDefaultRepositories(includeAllEntities: true) |
Use AddDefaultRepositories() only for aggregate roots |
Inject DbContext in application/domain services |
Use IRepository<T> or custom repository interface |
Use DbContext directly outside the EF Core project |
Access via GetDbContextAsync() inside repository only |
DbContext Configuration
[ConnectionStringName("Default")]
public class MyProjectDbContext : AbpDbContext<MyProjectDbContext>
{
public DbSet<Book> Books { get; set; }
public DbSet<Author> Authors { get; set; }
public MyProjectDbContext(DbContextOptions<MyProjectDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Configure all entities
builder.ConfigureMyProject();
}
}
Entity Configuration
public static class MyProjectDbContextModelCreatingExtensions
{
public static void ConfigureMyProject(this ModelBuilder builder)
{
Check.NotNull(builder, nameof(builder));
builder.Entity<Book>(b =>
{
b.ToTable(MyProjectConsts.DbTablePrefix + "Books", MyProjectConsts.DbSchema);
b.ConfigureByConvention(); // ABP conventions (audit, soft-delete, etc.)
// Property configurations
b.Property(x => x.Name)
.IsRequired()
.HasMaxLength(BookConsts.MaxNameLength);
b.Property(x => x.Price)
.HasColumnType("decimal(18,2)");
// Indexes
b.HasIndex(x => x.Name);
// Relationships
b.HasOne<Author>()
.WithMany()
.HasForeignKey(x => x.AuthorId)
.OnDelete(DeleteBehavior.Restrict);
});
}
}
Repository Implementation
public class BookRepository : EfCoreRepository<MyProjectDbContext, Book, Guid>, IBookRepository
{
public BookRepository(IDbContextProvider<MyProjectDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
public async Task<Book> FindByNameAsync(
string name,
bool includeDetails = true,
CancellationToken cancellationToken = default)
{
var dbSet = await GetDbSetAsync();
return await dbSet
.IncludeDetails(includeDetails)
.FirstOrDefaultAsync(
b => b.Name == name,
GetCancellationToken(cancellationToken));
}
public async Task<List<Book>> GetListByAuthorAsync(
Guid authorId,
bool includeDetails = false,
CancellationToken cancellationToken = default)
{
var dbSet = await GetDbSetAsync();
return await dbSet
.IncludeDetails(includeDetails)
.Where(b => b.AuthorId == authorId)
.ToListAsync(GetCancellationToken(cancellationToken));
}
public override async Task<IQueryable<Book>> WithDetailsAsync()
{
return (await GetQueryableAsync())
.Include(b => b.Reviews);
}
}
Extension Method for Include
public static class BookEfCoreQueryableExtensions
{
public static IQueryable<Book> IncludeDetails(
this IQueryable<Book> queryable,
bool include = true)
{
if (!include)
{
return queryable;
}
return queryable
.Include(b => b.Reviews);
}
}
Migration Commands
# Navigate to EF Core project
cd src/MyProject.EntityFrameworkCore
# Add migration
dotnet ef migrations add MigrationName
# Apply migration (choose one):
dotnet run --project ../MyProject.DbMigrator # Recommended - also seeds data
dotnet ef database update # EF Core command only
# Remove last migration (if not applied)
dotnet ef migrations remove
# Generate SQL script
dotnet ef migrations script
Note: ABP templates include
IDesignTimeDbContextFactoryin the EF Core project, so-s(startup project) parameter is not needed.
Module Configuration
[DependsOn(typeof(AbpEntityFrameworkCoreModule))]
public class MyProjectEntityFrameworkCoreModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAbpDbContext<MyProjectDbContext>(options =>
{
// Add default repositories for aggregate roots only (DDD best practice)
options.AddDefaultRepositories();
// ⚠️ Avoid includeAllEntities: true - it creates repositories for child entities,
// allowing them to be modified without going through the aggregate root,
// which breaks data consistency
});
Configure<AbpDbContextOptions>(options =>
{
options.UseSqlServer(); // or UseNpgsql(), UseMySql(), etc.
});
}
}
Best Practices
Repositories for Aggregate Roots Only
Don't use includeAllEntities: true in AddDefaultRepositories(). This creates repositories for child entities, allowing direct modification without going through the aggregate root - breaking DDD data consistency rules.
// ✅ Correct - Only aggregate roots get repositories
options.AddDefaultRepositories();
// ❌ Avoid - Creates repositories for ALL entities including child entities
options.AddDefaultRepositories(includeAllEntities: true);
Always Call ConfigureByConvention
builder.Entity<MyEntity>(b =>
{
b.ConfigureByConvention(); // Don't forget this!
// Other configurations...
});
Use Table Prefix
public static class MyProjectConsts
{
public const string DbTablePrefix = "App";
public const string DbSchema = null; // Or "myschema"
}
Performance Tips
- Add explicit indexes for frequently queried fields
- Use
AsNoTracking()for read-only queries - Avoid N+1 queries with
.Include()or specifications - ABP handles cancellation automatically; use
GetCancellationToken(cancellationToken)only in custom repository methods - Consider query splitting for complex queries with multiple collections
Accessing Raw DbContext
public async Task CustomOperationAsync()
{
var dbContext = await GetDbContextAsync();
// Raw SQL
await dbContext.Database.ExecuteSqlRawAsync(
"UPDATE Books SET IsPublished = 1 WHERE AuthorId = {0}",
authorId
);
}
Data Seeding
public class MyProjectDataSeedContributor : IDataSeedContributor, ITransientDependency
{
private readonly IRepository<Book, Guid> _bookRepository;
private readonly IGuidGenerator _guidGenerator;
public async Task SeedAsync(DataSeedContext context)
{
if (await _bookRepository.GetCountAsync() > 0)
{
return;
}
await _bookRepository.InsertAsync(
new Book(_guidGenerator.Create(), "Sample Book", 19.99m, Guid.Empty),
autoSave: true
);
}
}
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?