Overview
Silky integrates Entity Framework Core data access via the Silky.EntityFrameworkCore package, providing a repository pattern with full CRUD support for multiple databases (SQL Server, MySQL, PostgreSQL, SQLite, Oracle, etc.). It integrates seamlessly with Silky's DI container and distributed transactions.
Key features:
- Generic repository interface (
IRepository<TEntity>) with complete CRUD operations - Multiple
DbContextsupport (multi-database scenarios) - Unit of Work support
- Code First + database migrations
- Integration with TCC distributed transactions
Installation
PM> Install-Package Silky.EntityFrameworkCore -Version 3.9.2
# Optional extensions (soft delete, data scope filtering, etc.)
PM> Install-Package Silky.EntityFrameworkCore.Extras -Version 3.9.2
Register EFCore Services
public class ConfigureService : IConfigureService
{
public void ConfigureServices(IServiceCollection services, IConfiguration configuration)
{
services.AddDatabaseAccessor(options =>
{
// Register primary database context
options.AddDbPool<DefaultDbContext>(DbProvider.MySql);
}, "YourService.Database.Migrations");
}
}
Define DbContext
Inherit from AbstractDbContext<TDbContext>:
using Microsoft.EntityFrameworkCore;
using Silky.EntityFrameworkCore.Contexts;
using Silky.EntityFrameworkCore.Locators;
public class DefaultDbContext : AbstractDbContext<DefaultDbContext, MasterDbContextLocator>
{
public DefaultDbContext(DbContextOptions<DefaultDbContext> options) : base(options)
{
}
}
Define Entities
Implement IEntity or inherit from Entity<TKey> (recommended — includes Id, CreatedTime, and UpdatedTime):
using Silky.EntityFrameworkCore.Entities;
public class Order : Entity<long>
{
public string OrderNo { get; set; }
public decimal TotalAmount { get; set; }
public string Status { get; set; }
}
Using the Repository
Inject IRepository<TEntity> directly:
public class OrderAppService : IOrderAppService, IScopedDependency
{
private readonly IRepository<Order> _orderRepository;
public OrderAppService(IRepository<Order> orderRepository)
{
_orderRepository = orderRepository;
}
public async Task<OrderOutput> CreateAsync(CreateOrderInput input)
{
var order = input.MapTo<Order>();
order = await _orderRepository.InsertNowAsync(order);
return order.MapTo<OrderOutput>();
}
public async Task<OrderOutput> GetAsync(long id)
{
var order = await _orderRepository.FindAsync(id);
return order.MapTo<OrderOutput>();
}
public async Task<List<OrderOutput>> GetListAsync()
{
return await _orderRepository
.AsQueryable()
.ProjectToType<OrderOutput>()
.ToListAsync();
}
}
Common Repository Methods
| Method | Description |
|---|---|
InsertAsync / InsertNowAsync | Insert entity (NowAsync saves immediately) |
UpdateAsync / UpdateNowAsync | Update entity |
DeleteAsync / DeleteNowAsync | Delete entity |
FindAsync(id) | Find by primary key |
FirstOrDefaultAsync(predicate) | Find first matching entity |
AsQueryable() | Return IQueryable<T> for LINQ queries |
AnyAsync(predicate) | Check if any entity matches |
CountAsync(predicate) | Count matching entities |
Database Migrations
# Add migration
dotnet ef migrations add InitialCreate --project YourService.Database.Migrations
# Apply to database
dotnet ef database update
To auto-apply migrations at startup:
public class AppModule : SilkyModule
{
public override async Task Initialize(ApplicationContext context)
{
await context.ServiceProvider
.GetRequiredService<IDbContextMigrationManager>()
.MigrateAsync();
}
}
Multiple Database Contexts
// Define a secondary locator
public class SlaveDbContextLocator : IDbContextLocator { }
// Register the secondary context
options.AddDbPool<SlaveDbContext, SlaveDbContextLocator>(DbProvider.PostgreSql, connectionString);
// Inject a repository bound to the secondary database
private readonly IRepository<Product, SlaveDbContextLocator> _productRepository;
Soft Delete
With Silky.EntityFrameworkCore.Extras, implement ISoftDelete on entities to enable soft deletion:
public class Order : Entity<long>, ISoftDelete
{
public bool IsDeleted { get; set; }
public DateTimeOffset? DeletedTime { get; set; }
}
DeleteAsync will set IsDeleted = true instead of physically removing the row. All queries automatically filter out soft-deleted records.
