-
-
Notifications
You must be signed in to change notification settings - Fork 10
Repositories for SQL databases (EF Core)
Modern generic repositories for SQL databases are built on top of the following ORM frameworks: EF Core and Dapper.
To use EF Core repository install the Modern.Repositories.EFCore.DependencyInjection
Nuget package and register it within Modern builder in DI:
builder.Services
.AddModern()
.AddRepositoriesEfCore(options =>
{
options.AddRepository<FlyingDbContext, AirplaneDbo, long>(useDbFactory: false);
});
Specify the type of EF Core DbContext, Dbo entity model and primary key.
useDbFactory
parameter indicates whether repository with DbContextFactory should be used. The default value is false
.
ℹ️ Use this parameter if you plan to inherit from this generic repository and extend or change its functionality.
When usingDbContextFactory
every repository creates and closes a database connection in each method.
When NOT usingDbContextFactory
repository shares the same database connection during its lifetime.
⚠️ It is not recommended to useuseDbFactory = false
when repository is registered as SingleInstance, otherwise a single database connection will persist during the whole application lifetime
Modern generic repositories are flexible, easily changeable and extendable. New methods can be added to repository as well as each method can be overriden.
The following interfaces can be inherited from:
IModernCrudRepository<TEntity, TId>
IModernQueryRepository<TEntity, TId>
Or inherit from a combined interface:
IModernRepository<TEntity, TId> : IModernCrudRepository<TEntity, TId>, IModernQueryRepository<TEntity, TId>
Lets have a look at example of inheritance from ModernEfCoreRepository:
public interface IAirplaneRepository : IModernRepository<AirplaneDbo, long>
{
}
public class AirplaneRepository : ModernEfCoreRepositoryWithFactory<FlyingDbContext, AirplaneDbo, long>, IAirplaneRepository
{
public AirplaneRepository(IDbContextFactory<FlyingDbContext> dbContextFactory, IOptions<EfCoreRepositoryConfiguration?> configuration)
: base(dbContextFactory, configuration)
{
}
// Override GetEntityId
protected override long GetEntityId(AirplaneDbo entity) => entity.Id;
// Override GetEntityIncludeQuery to include Airplane Model
protected override EntityIncludeQuery<AirplaneDbo> GetEntityIncludeQuery()
=> new(query => query.Include(t => t.Model));
// Override CreateAsync to select existing Airplane Model
public override async Task<AirplaneDbo> CreateAsync(AirplaneDbo entity, CancellationToken cancellationToken = default)
{
await using var dbContext = await DbContextFactory.CreateDbContextAsync(cancellationToken);
var model = await dbContext.AirplaneModels.FirstOrDefaultAsync(x => x.Name == entity.Model.Name, cancellationToken);
if (model is not null)
{
entity.Model = model;
}
await dbContext.Airplanes.AddAsync(entity, cancellationToken);
await dbContext.SaveChangesAsync(cancellationToken);
return entity;
}
// Override CreateAsync(list) to select existing Airplane Model
public override async Task<List<AirplaneDbo>> CreateAsync(List<AirplaneDbo> entities, CancellationToken cancellationToken = default)
{
await using var dbContext = await DbContextFactory.CreateDbContextAsync(cancellationToken);
foreach (var entity in entities)
{
var model = await dbContext.AirplaneModels.FirstOrDefaultAsync(x => x.Name == entity.Model.Name, cancellationToken);
if (model is not null)
{
entity.Model = model;
}
await dbContext.Airplanes.AddAsync(entity, cancellationToken);
}
await dbContext.SaveChangesAsync(cancellationToken);
return entities;
}
}