From ABP Sensei
Guides ABP Framework EF Core integration: DbContext setup, entity mapping with ConfigureByConvention, repository registration, and DBMS configuration (PostgreSQL, MySQL, SQLite, Oracle).
How this skill is triggered — by the user, by Claude, or both
Slash command
/abp-sensei:abp-efcoreThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
A guide to EF Core integration in ABP Framework v10.4. DbContext, repository, migration, eager/lazy loading, and advanced topics.
A guide to EF Core integration in ABP Framework v10.4. DbContext, repository, migration, eager/lazy loading, and advanced topics.
abp add-package Volo.Abp.EntityFrameworkCore
using Microsoft.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
namespace MyCompany.MyProject
{
public class MyDbContext : AbpDbContext<MyDbContext>
{
public DbSet<Book> Books { get; set; }
public DbSet<Author> Authors { get; set; }
public MyDbContext(DbContextOptions<MyDbContext> options)
: base(options) { }
}
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<Book>(b =>
{
b.ToTable("Books");
b.ConfigureByConvention(); // REQUIRED for base properties
b.Property(x => x.Name).IsRequired().HasMaxLength(128);
b.HasIndex(x => x.Name);
});
}
ConfigureByConvention() must always be called — it automatically configures base class properties (Id, CreationTime, etc.).
[DependsOn(typeof(AbpEntityFrameworkCoreModule))]
public class MyModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAbpDbContext<MyDbContext>(options =>
{
options.AddDefaultRepositories(); // Automatic repository for AggregateRoots
// options.AddDefaultRepositories(includeAllEntities: true); // For all entities
});
}
}
abp new Acme.BookStore -dbms PostgreSQL
abp new Acme.BookStore -dbms MySQL
abp new Acme.BookStore -dbms SQLite
abp new Acme.BookStore -dbms Oracle
PostgreSQL:
# 1. Remove the Volo.Abp.EntityFrameworkCore.SqlServer package
# 2. Add the Volo.Abp.EntityFrameworkCore.PostgreSql package
// Change the module dependency
[DependsOn(typeof(AbpEntityFrameworkCorePostgreSqlModule))] // instead of SqlServer
// Use UseNpgsql()
Configure<AbpDbContextOptions>(options => options.UseNpgsql());
// Also use UseNpgsql() in the DbContextFactory
// Enable legacy timestamp behavior (Npgsql 6.0+)
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
MySQL (Pomelo):
Configure<AbpDbContextOptions>(options =>
{
options.Configure(ctx =>
{
if (ctx.ExistingConnection != null)
ctx.DbContextOptions.UseMySql(ctx.ExistingConnection);
else
ctx.DbContextOptions.UseMySql(ctx.ConnectionString);
});
});
// Set the DBMS provider for modules like OpenIddict (default auth server in ABP v6.0+: OpenIddict)
builder.ConfigureOpenIddict(options =>
{
options.DatabaseProvider = EfCoreDatabaseProvider.MySql;
});
SQLite:
Configure<AbpDbContextOptions>(options => options.UseSqlite());
| DBMS | Package |
|---|---|
| SQL Server | Volo.Abp.EntityFrameworkCore.SqlServer |
| PostgreSQL | Volo.Abp.EntityFrameworkCore.PostgreSql |
| MySQL | Volo.Abp.EntityFrameworkCore.MySQL |
| SQLite | Volo.Abp.EntityFrameworkCore.Sqlite |
| Oracle | Volo.Abp.EntityFrameworkCore.Oracle |
[ConnectionStringName("MySecondConnString")]
public class MyDbContext : AbpDbContext<MyDbContext> { }
If not specified, the Default connection string is used.
public class BookManager : DomainService
{
private readonly IRepository<Book, Guid> _bookRepository;
public BookManager(IRepository<Book, Guid> bookRepository)
{
_bookRepository = bookRepository;
}
public async Task<Book> CreateBookAsync(string name, BookType type)
{
var book = new Book(GuidGenerator.Create(), name, type);
await _bookRepository.InsertAsync(book);
return book;
}
}
// Interface (Domain layer)
public interface IBookRepository : IRepository<Book, Guid>
{
Task DeleteBooksByType(BookType type);
}
// Implementation (EF Core layer)
public class BookRepository : EfCoreRepository<BookStoreDbContext, Book, Guid>, IBookRepository
{
public BookRepository(IDbContextProvider<BookStoreDbContext> dbContextProvider)
: base(dbContextProvider) { }
public async Task DeleteBooksByType(BookType type)
{
var dbContext = await GetDbContextAsync();
await dbContext.Database.ExecuteSqlRawAsync(
$"DELETE FROM Books WHERE Type = {(int)type}"
);
}
}
context.Services.AddAbpDbContext<BookStoreDbContext>(options =>
{
options.AddDefaultRepositories();
options.AddRepository<Book, BookRepository>(); // BookRepository is used instead of IRepository<Book, Guid>
});
// Repository.WithDetailsAsync
var queryable = await _orderRepository.WithDetailsAsync(x => x.Lines);
var orders = await AsyncExecuter.ToListAsync(queryable);
// DefaultWithDetailsFunc configuration
Configure<AbpEntityOptions>(options =>
{
options.Entity<Order>(orderOptions =>
{
orderOptions.DefaultWithDetailsFunc = query => query.Include(o => o.Lines);
});
});
// It can then be used without a parameter
var queryable = await _orderRepository.WithDetailsAsync();
var order = await _orderRepository.GetAsync(id); // includeDetails: true (default)
var order = await _orderRepository.GetAsync(id, includeDetails: false);
var orders = await _orderRepository.GetListAsync(includeDetails: true);
var order = await _orderRepository.GetAsync(id, includeDetails: false);
await _orderRepository.EnsureCollectionLoadedAsync(order, x => x.Lines);
// order.Lines is now populated
// 1. Install the Microsoft.EntityFrameworkCore.Proxies package
// 2. Configuration
Configure<AbpDbContextOptions>(options =>
{
options.PreConfigure<MyDbContext>(opts =>
{
opts.DbContextOptions.UseLazyLoadingProxies();
});
options.UseSqlServer();
});
// 3. Make navigation properties virtual
public virtual ICollection<OrderLine> Lines { get; set; }
public virtual Order Order { get; set; }
// No-Tracking is applied automatically
public class MyService : ApplicationService
{
private readonly IReadOnlyRepository<Book, Guid> _bookRepository;
// When tracking is needed
var query = (await _bookRepository.GetQueryableAsync()).AsTracking();
}
ObjectExtensionManager.Instance
.MapEfCoreProperty<IdentityRole, string>(
"Title",
(entityBuilder, propertyBuilder) =>
{
propertyBuilder.HasMaxLength(64);
}
);
MapEfCorePropertymust be called before the DbContext is used. In startup templates, theEfCoreEntityExtensionMappingsclass is the safe spot.
Configure<AbpDbContextOptions>(options =>
{
options.UseSqlServer(optionsBuilder =>
{
optionsBuilder.UseQuerySplittingBehavior(QuerySplittingBehavior.SingleQuery);
});
});
[IgnoreMultiTenancy] // Always use the host connection string
public class TenantManagementDbContext : AbpDbContext<TenantManagementDbContext> { }
public class MyRepositoryBase<TEntity> : EfCoreRepository<BookStoreDbContext, TEntity>
where TEntity : class, IEntity
{
public MyRepositoryBase(IDbContextProvider<BookStoreDbContext> dbContextProvider)
: base(dbContextProvider) { }
}
// Registration
context.Services.AddAbpDbContext<BookStoreDbContext>(options =>
{
options.SetDefaultRepositoryClasses(
typeof(MyRepositoryBase<,>),
typeof(MyRepositoryBase<>)
);
});
ConfigureByConvention() — for base property mappingIAsyncQueryableExecuterWithDetailsAsync — to avoid the N+1 problemIReadOnlyRepository for read-only queries — No-Tracking is automaticAdd-Migration, Update-Database# Create a migration
dotnet ef migrations add InitialCreate --project Acme.BookStore.EntityFrameworkCore --startup-project Acme.BookStore.DbMigrator
# Apply the migration
dotnet ef database update --project Acme.BookStore.EntityFrameworkCore --startup-project Acme.BookStore.DbMigrator
# or run the DbMigrator
dotnet run --project Acme.BookStore.DbMigrator
// A separate migration folder for each DbContext
builder.Entity<Book>(b => { ... }); // BookStoreDbContext
// Migration design
public class BookStoreDbContextModelSnapshot : ModelSnapshot { }
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.InsertData(
table: "Books",
columns: new[] { "Id", "Name", "Price" },
values: new object[] { Guid.NewGuid(), "1984", 29.99m }
);
}
Combining multiple DbContexts into a single DbContext:
// Define an interface
public interface IBookStoreDbContext : IEfCoreDbContext
{
DbSet<Book> Books { get; }
}
// Have the DbContext implement the interface
public class BookStoreDbContext : AbpDbContext<BookStoreDbContext>, IBookStoreDbContext
{
public DbSet<Book> Books { get; set; }
}
// Register the default repositories with the interface
context.Services.AddAbpDbContext<BookStoreDbContext>(options =>
{
options.AddDefaultRepositories<IBookStoreDbContext>();
});
// Another DbContext can replace this interface
[ReplaceDbContext(typeof(IBookStoreDbContext))]
public class UnifiedDbContext : AbpDbContext<UnifiedDbContext>, IBookStoreDbContext
{
public DbSet<Book> Books { get; set; }
}
public class MyCustomEfCoreBulkOperationProvider : IEfCoreBulkOperationProvider, ITransientDependency
{
public async Task InsertManyAsync<TDbContext, TEntity>(
IEfCoreRepository<TEntity> repository,
IEnumerable<TEntity> entities,
bool autoSave,
CancellationToken cancellationToken)
{
// Custom bulk insert logic (e.g. EFCore.BulkExtensions)
}
public async Task UpdateManyAsync<TDbContext, TEntity>(...) { }
public async Task DeleteManyAsync<TDbContext, TEntity>(...) { }
}
Provides CDSS development patterns for drug interaction checking, dose validation, clinical scoring (NEWS2, qSOFA), and alert classification integrated into EMR workflows.
npx claudepluginhub burakdmir/abp-skills --plugin abp-sensei