repositories - Envivo-Software/Envivo.Fresnel GitHub Wiki

Repositories

Repositories provide a convenient facade over your persistent data store. Instead of scattering database access code throughout your model, use Repositories to encapsulate that logic.

To create a repository, implement the IRepository<T> interface. The following shows a simple example that keeps the objects in memory:

/// <summary>
/// Repository for managing Products in a data store
/// </summary>
public class ProductRepository : IRepository<Product> //👈
{
    private readonly InMemoryRepository<Product> _InMemoryRepository;

    public ProductRepository(DemoProductsBuilder demoProductsBuilder)
    {
        _InMemoryRepository = new InMemoryRepository<Product>(demoProductsBuilder.Build());
    }

    /// <summary>
    /// <inheritdoc/>
    /// </summary>
    /// <returns></returns>
    public IQueryable<Product> GetQuery()
    {
        return _InMemoryRepository.GetQuery();
    }

    /// <summary>
    /// <inheritdoc/>
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public Task<Product> LoadAsync(Guid id)
    {
        return _InMemoryRepository.LoadAsync(id);
    }

    /// <summary>
    /// <inheritdoc/>
    /// </summary>
    /// <param name="aggregateRoot"></param>
    /// <param name="newObjects"></param>
    /// <param name="modifiedObjects"></param>
    /// <param name="deletedObjects"></param>
    /// <returns></returns>
    public Task<int> SaveAsync(Product aggregateRoot, IEnumerable<object> newObjects, IEnumerable<object> modifiedObjects, IEnumerable<object> deletedObjects)
    {
        return _InMemoryRepository.SaveAsync(aggregateRoot, newObjects, modifiedObjects, deletedObjects);
    }

    /// <summary>
    /// <inheritdoc/>
    /// </summary>
    /// <param name="aggregateRoot"></param>
    /// <returns></returns>
    public Task DeleteAsync(Product aggregateRoot)
    {
        return _InMemoryRepository.DeleteAsync(aggregateRoot);
    }
}

You can inject this repository into any other dependency, and thus guarantee data access via this centralised class.

In the following example, we refactored the ProductQuerySpecification (from the Query Specifications section) to use ProductRepository, instead of using an internal list:

/// <summary>
/// Used to query for Products
/// </summary>
public class ProductQuerySpecification : IQuerySpecification<Product>
{
    private readonly IRepository<Product> _ProductRepo;

    /// <summary>
    /// <inheritdoc/>
    /// </summary>
    /// <param name="productRepo"></param>
    public ProductQuerySpecification(IRepository<Product> productRepo)
    {
        _ProductRepo = productRepo;
    }

    /// <summary>
    /// <inheritdoc/>
    /// </summary>
    /// <returns></returns>
    public Task<IEnumerable<Product>> GetResultsAsync()
    {
        return Task.FromResult(_ProductRepo.GetQuery().AsEnumerable());
    }
}

💡 Developer Tips

If your domain model requires lots of custom database queries, use separate Query Specifications instead of adding methods to your Repositories.

⚠️ **GitHub.com Fallback** ⚠️