.agents/skills/abp-ef-core/SKILL.md
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.
npx skillsauth add afonsoft/VideoChat abp-ef-coreInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Docs: https://abp.io/docs/latest/framework/data/entity-framework-core
| 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 |
[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();
}
}
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);
});
}
}
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);
}
}
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);
}
}
# 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.
[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.
});
}
}
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);
builder.Entity<MyEntity>(b =>
{
b.ConfigureByConvention(); // Don't forget this!
// Other configurations...
});
public static class MyProjectConsts
{
public const string DbTablePrefix = "App";
public const string DbSchema = null; // Or "myschema"
}
AsNoTracking() for read-only queries.Include() or specificationsGetCancellationToken(cancellationToken) only in custom repository methodspublic async Task CustomOperationAsync()
{
var dbContext = await GetDbContextAsync();
// Raw SQL
await dbContext.Database.ExecuteSqlRawAsync(
"UPDATE Books SET IsPublished = 1 WHERE AuthorId = {0}",
authorId
);
}
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
);
}
}
development
This skill enables visual inspection of websites running locally or remotely to identify and fix design issues. Triggers on requests like "review website design", "check the UI", "fix the layout", "find design problems". Detects issues with responsive design, accessibility, visual consistency, and layout breakage, then performs fixes at the source code level.
testing
Comprehensive unit testing with xUnit, mocking, test patterns, and best practices for .NET applications
data-ai
Universal SQL performance optimization assistant for comprehensive query tuning, indexing strategies, and database performance analysis across all SQL databases (MySQL, PostgreSQL, SQL Server, Oracle). Provides execution plan analysis, pagination optimization, batch operations, and performance monitoring guidance.
development
Universal SQL code review assistant that performs comprehensive security, maintainability, and code quality analysis across all SQL databases (MySQL, PostgreSQL, SQL Server, Oracle). Focuses on SQL injection prevention, access control, code standards, and anti-pattern detection. Complements SQL optimization prompt for complete development coverage.