Skip to main content

Repositories

Repository Pattern in Ramsha

The repository pattern in Ramsha provides a clean abstraction layer between your domain logic and data access code. It offers both default implementations for common operations and flexibility to create custom repositories when needed.

Overview

Ramsha's repository system provides:

  • Default repositories for common CRUD operations
  • Custom repositories for domain-specific queries
  • Automatic registration through fluent configuration
  • Unit of Work integration for transaction management

Quick Start

1. Define Your Entity

public sealed class Product : Entity<Guid>
{
public string Name { get; set; }
public decimal Price { get; set; }
public Guid CategoryId { get; set; }
public Category Category { get; set; }
}

2. Enable The Default Repositories Registration

public class AppModule : RamshaModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddRamshaDbContext<AppDbContext>(options =>
{
// this will Add default repositories for all entities
options.AddDefaultRepositories(true);
});
}
}

Base Repository Interface

Ramsha provides a Generic and base interfaces for repositories:

Base Repository Interfaces

// Marker interface for all repositories
public interface IRepository { }

// Repository for entities without specifying ID type
public interface IRepository<TEntity> : IRepository
where TEntity : IEntity
{
Task<TEntity?> AddAsync(TEntity entity);
Task<List<TEntity>> GetListAsync();
// others common methods
}

// Repository for entities with specific ID type
public interface IRepository<TEntity, TId> : IRepository<TEntity>
where TId : IEquatable<TId>
where TEntity : IEntity<TId>
{
Task<bool> DeleteAsync(TId id);
Task<TEntity?> FindAsync(TId id);
// others common methods
}

Default Repositories

Using Default Repository Implementation

When you register default repositories, Ramsha automatically provides implementations for common operations:

// Registration
options.AddDefaultRepositories(true); // For all entities

or

options.AddDefaultRepository<Product>();  // For specific entity

So you can use in service

public class ProductService
{
private readonly IRepository<Product, Guid> _productRepository;

public ProductService(IRepository<Product, Guid> productRepository)
{
_productRepository = productRepository;
}

public async Task<Product?> GetProductAsync(Guid id)
{
return await _productRepository.FindAsync(id);
}

public async Task<List<Product>> GetExpensiveProductsAsync()
{
return await _productRepository.GetListAsync(
p => p.Price > 1000
);
}
}

Custom Repositories

Creating a Custom Repository

When you need domain-specific query logic, create a custom repository:

1. Define Repository Interface

public interface IProductRepository : IRepository<Product, Guid>
{
// Custom methods for domain-specific queries
Task<List<Product>> GetProductsByCategoryAsync(Guid categoryId);
// other methods
}

2. Implement Custom Repository

public class ProductRepository : EFCoreRepository<AppDbContext, Product, Guid>, IProductRepository
{
public async Task<List<Product>> GetProductsByCategoryAsync(Guid categoryId)
{
var context = await GetDbContextAsync();
return await context.Set<Product>()
.Where(p => p.CategoryId == categoryId)
.ToListAsync();
}
}

3. Register Custom Repository

context.Services.AddRamshaDbContext<AppDbContext>(options =>
{
options.AddRepository<Product, IProductRepository, ProductRepository>();
});

4. Use Custom Repository

public class ProductAppService(IProductRepository productRepository)
{
public async Task<decimal> CalculateCategoryValueAsync(Guid categoryId)
{
var products = await productRepository.GetProductsByCategoryAsync(categoryId);
return products.Sum(p => p.Price);
}
}

Advanced Usage

Custom Repository Base Classes

You can create a custom base repositories and replace the default:

public class AppRepository<TEntity> 
: EFCoreRepository<AppDbContext, TEntity>
where TEntity : class, IEntity
{
// add here Shared methods
}
public class AppRepository<TEntity, TKey>
: EFCoreRepository<AppDbContext, TEntity, TKey>
where TEntity : class, IEntity<TKey>
where TKey : IEquatable<TKey>
{
// add here Shared methods
}

Then Configure Options:

context.Services.AddRamshaDbContext<AppDbContext>(options =>
{
//...
options.SetDefaultRepositoryClasses(
typeof(AppRepository<,>),
typeof(AppRepository<>)
);
});

Next Steps