Sagittaras.Repository by Sagittaras Games
Implementation of Generic Repository Pattern.
Repository pattern provides an extra layer for accessing entities data in database without direct access to database context class.
Your entity operations and queries are grouped together in one single class.
To define your repository just extends Repository<TEntity, TKey>
class, providing the type of entity
and the type of its primary key.
public class AuthorRepository : Repository<Author, Guid>
{
public AuthorRepository(DbContext dbContext) : base(dbContext)
{
}
}
If your entity is using composite key (only two primary keys are supported), extends instead Repository<TEntity, TFirstKey, TSecondKey>
class.
public class BookTagRepository : Repository<BookTag, Guid, int>
{
public BookTagRepository(DbContext dbContext) : base(dbContext)
{
}
}
When you prefer to describe your repositories by interfaces, you can simply use interfaces equivalents to base classes.
public interface IAuthorRepository : IRepository<Author, Guid>
{
Task<Author> GetByEmail(string email);
}
And then our repository...
public class AuthorRepository : Repository<Author, Guid>, IAuthorRepository
{
public BookTagRepository(DbContext dbContext) : base(dbContext)
{
}
public Task<Author> GetByEmail(string email)
{
throw new NotImplementedException();
}
}
Repositories can be easily registered to Dependency Container via extension method for the IServiceCollection
.
ServiceCollection services = new();
services.UseRepositoryPattern(options =>
{
options.AddRepository<IAuthorRepository, AuthorRepository>();
options.AddRepository<BookRepository>();
options.AddRepository<PublisherRepository>();
options.AddRepository<BookTagRepository>();
});
Repositories can be registered only by their type or in combination with interface. All registered repositories
are also registered under the IRepository
type.
Current lifetime of repositories is Scoped.
The repository is providing Queryable
property, which can be used to read the data from database.
public class AuthorRepository : Repository<Author, Guid>, IAuthorRepository
{
public BookTagRepository(DbContext dbContext) : base(dbContext)
{
}
public async Task<Author> GetByEmail(string email)
{
return await Queryable.SingleAsync(e => e.Email == email);
}
}
Repository is providing methods for Insert
, Update
, Remove
and their Range equivalents.
IAuthorRepository repo = ServiceProvider.GetService<IAuthorRepository>();
Author author = new(){
Email = "john.doe@example.com",
FirstName = "John",
LastName = "Doe"
}
repo.Insert(author);
await repo.SaveChangesAsync();
CRUD operations made to the repository needs to be saved by SaveChanges()
or SaveChangesAsync()
methods on
Repository. This methods writes all unapplied changes to database context and saves them to the database.
Repository also provides a Join<TAnotherEntity>()
method, which can be used in join statements, to join another
DbSets in the query.