Standard Implementation of REN Repository

Here is the standard implementation of RENRepository which allows you to use pre-defined Repository:

  1. INTERFACE:

public interface IRENRepository<TEntity> where TEntity : class
{
    #region Create

    /// <summary>
    ///     Inserts a single entity into the repository.
    /// </summary>
    /// <param name="entity">The entity to insert.</param>
    void Insert(TEntity entity);

    /// <summary>
    ///     Inserts a single entity into the repository asynchronously.
    /// </summary>
    /// <param name="entity">The entity to insert asynchronously.</param>
    /// <param name="cancellationToken">Optional cancellationToken.</param>
    /// <returns>A task representing the asynchronous operation.</returns>
    Task InsertAsync(TEntity entity, CancellationToken cancellationToken = default);
    
    /// <summary>
    ///     Inserts list of entities into the repository.
    /// </summary>
    /// <param name="entities">The entity list to insert.</param>
    void Insert(IEnumerable<TEntity> entities);

    /// <summary>
    ///     Inserts list of entities into the repository asynchronously.
    /// </summary>
    /// <param name="entities">The entity list to insert asynchronously.</param>
    /// <param name="cancellationToken">Optional cancellationToken.</param>
    /// <returns>A task representing the asynchronous operation.</returns>
    Task InsertAsync(IEnumerable<TEntity> entities, CancellationToken cancellationToken = default);

    /// <summary>
    ///     Bulk inserts a list of entities into the repository.
    /// </summary>
    /// <param name="entities">The list of entities to insert.</param>
    void BulkInsert(IEnumerable<TEntity> entities, BulkConfig? bulkConfig = null);

    /// <summary>
    ///     Bulk inserts a list of entities into the repository asynchronously.
    /// </summary>
    /// <param name="entities">The list of entities to insert asynchronously.</param>
    /// <param name="cancellationToken">Optional cancellationToken.</param>
    /// <returns>A task representing the asynchronous operation.</returns>
    Task BulkInsertAsync(IEnumerable<TEntity> entities, BulkConfig? bulkConfig = null, CancellationToken cancellationToken = default);
    #endregion

    #region Read

    /// <summary>
    ///     Gets a queryable collection of entities from the repository.
    /// </summary>
    /// <param name="filter">An optional filter expression.</param>
    /// <param name="orderBy">An optional ordering expression.</param>
    /// <param name="include">An optional include expression.</param>
    /// <param name="isReadOnly">A flag indicating if the query is read-only.</param>
    /// <returns>A queryable collection of entities.</returns>
    IQueryable<TEntity> GetQueryable(Expression<Func<TEntity, bool>>? filter = null,
        Expression<Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>>? orderBy = null,
        Expression<Func<IQueryable<TEntity>, IQueryable<TEntity>>>? include = null, bool isReadOnly = false);

    /// <summary>
    ///     Gets a queryable collection of entities from the repository asynchronously.
    /// </summary>
    /// <param name="filter">An optional filter expression.</param>
    /// <param name="orderBy">An optional ordering expression.</param>
    /// <param name="include">An optional include expression.</param>
    /// <param name="isReadOnly">A flag indicating if the query is read-only.</param>
    /// <param name="cancellationToken">Optional cancellationToken.</param>
    /// <returns>A task representing the queryable collection of entities.</returns>
    Task<IQueryable<TEntity>> GetQueryableAsync(Expression<Func<TEntity, bool>>? filter = null,
        Expression<Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>>? orderBy = null,
        Expression<Func<IQueryable<TEntity>, IQueryable<TEntity>>>? include = null, bool isReadOnly = false,
        CancellationToken cancellationToken = default);

    /// <summary>
    ///     Gets a list of entities from the repository.
    /// </summary>
    /// <param name="filter">An optional filter expression.</param>
    /// <param name="orderBy">An optional ordering expression.</param>
    /// <param name="include">An optional include expression.</param>
    /// <param name="isReadOnly">A flag indicating if the query is read-only.</param>
    /// <returns>A list of entities.</returns>
    List<TEntity> GetList(Expression<Func<TEntity, bool>>? filter = null,
        Expression<Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>>? orderBy = null,
        Expression<Func<IQueryable<TEntity>, IQueryable<TEntity>>>? include = null, bool isReadOnly = false);

    /// <summary>
    ///     Gets a list of entities from the repository asynchronously.
    /// </summary>
    /// <param name="filter">An optional filter expression.</param>
    /// <param name="orderBy">An optional ordering expression.</param>
    /// <param name="include">An optional include expression.</param>
    /// <param name="isReadOnly">A flag indicating if the query is read-only.</param>
    /// <param name="cancellationToken">Optional cancellationToken.</param>
    /// <returns>A task representing the list of entities.</returns>
    Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>>? filter = null,
        Expression<Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>>? orderBy = null,
        Expression<Func<IQueryable<TEntity>, IQueryable<TEntity>>>? include = null, bool isReadOnly = false,
        CancellationToken cancellationToken = default);

    /// <summary>
    ///     Gets a single entity from the repository.
    /// </summary>
    /// <param name="filter">Required filter expression.</param>
    /// <param name="include">An optional include expression.</param>
    /// <param name="isReadOnly">A flag indicating if the query is read-only.</param>
    /// <returns>A single entity or null if not found.</returns>
    TEntity? GetSingle(Expression<Func<TEntity, bool>> filter,
        Expression<Func<IQueryable<TEntity>, IQueryable<TEntity>>>? include = null,
        bool isReadOnly = false);

    /// <summary>
    ///     Gets a single entity from the repository asynchronously.
    /// </summary>
    /// <param name="filter">Required filter expression.</param>
    /// <param name="include">An optional include expression.</param>
    /// <param name="isReadOnly">A flag indicating if the query is read-only.</param>
    /// <param name="cancellationToken">Optional cancellationToken.</param>
    /// <returns>A task representing the single entity or null if not found.</returns>
    Task<TEntity?> GetSingleAsync(Expression<Func<TEntity, bool>> filter,
        Expression<Func<IQueryable<TEntity>, IQueryable<TEntity>>>? include = null,
        bool isReadOnly = false,
        CancellationToken cancellationToken = default);

    #endregion

    #region Update

    /// <summary>
    ///     Updates a single entity in the repository.
    /// </summary>
    /// <param name="entity">The entity to update.</param>
    void Update(TEntity entity);

    /// <summary>
    ///     Updates a single entity in the repository asynchronously.
    /// </summary>
    /// <param name="entity">The entity to update asynchronously.</param>
    /// <param name="cancellationToken">Optional cancellationToken.</param>
    /// <returns>A task representing the asynchronous operation.</returns>
    Task UpdateAsync(TEntity entity, CancellationToken cancellationToken = default);
    
    /// <summary>
    ///     Bulk updates multiple entities in the repository.
    /// </summary>
    /// <param name="entity">The entities to update.</param>
    void BulkUpdate(IEnumerable<TEntity> entities, BulkConfig? bulkConfig = null);
    
    /// <summary>
    ///     Bulk updates multiple entities in the repository asynchronously.
    /// </summary>
    /// <param name="entity">The entities to update asynchronously.</param>
    /// <param name="cancellationToken">Optional cancellationToken.</param>
    /// <returns>A task representing the asynchronous operation.</returns>
    Task BulkUpdateAsync(IEnumerable<TEntity> entities, BulkConfig? bulkConfig = null, CancellationToken cancellationToken = default);
    #endregion

    #region Delete

    /// <summary>
    ///     Deletes a single entity from the repository.
    /// </summary>
    /// <param name="entity">The entity to delete.</param>
    void Delete(TEntity entity);

    /// <summary>
    ///     Deletes a single entity from the repository asynchronously.
    /// </summary>
    /// <param name="entity">The entity to delete asynchronously.</param>
    /// <param name="cancellationToken">Optional cancellationToken.</param>
    /// <returns>A task representing the asynchronous operation.</returns>
    Task DeleteAsync(TEntity entity, CancellationToken cancellationToken = default);

    /// <summary>
    ///     Deletes a list of entities from the database.
    /// </summary>
    /// <param name="entities">The list of entities to delete.</param>
    void Delete(IEnumerable<TEntity> entities);

    /// <summary>
    ///     Deletes a list of entities from the database asynchronously.
    /// </summary>
    /// <param name="entities">The list of entities to delete asynchronously.</param>
    /// <param name="cancellationToken">Optional cancellationToken.</param>
    /// <returns>A task representing the asynchronous operation.</returns>
    Task DeleteAsync(IEnumerable<TEntity> entities, CancellationToken cancellationToken = default);

    /// <summary>
    ///     Bulk deletes a list of entities from the repository.
    /// </summary>
    /// <param name="entities">The list of entities to delete asynchronously.</param>{{}
    void BulkDelete(IEnumerable<TEntity> entities, BulkConfig? bulkConfig = null);
    
    /// <summary>
    ///     Bulk deletes a list of entities from the repository asynchronously.
    /// </summary>
    /// <param name="entities">The list of entities to delete asynchronously.</param>
    /// <param name="cancellationToken">Optional cancellationToken.</param>
    /// <returns>A task representing the asynchronous operation.</returns>
    Task BulkDeleteAsync(IEnumerable<TEntity> entities, BulkConfig? bulkConfig = null, CancellationToken cancellationToken = default);
    #endregion
}
  1. CLASS:

public class RENRepository<TEntity> : IRENRepository<TEntity> where TEntity : class
{
    private readonly DbContext _context;
    private readonly DbSet<TEntity> _dbSet;

    /// <summary>
    ///     Initializes a new instance of the <see cref="RENRepository{TEntity}" /> class.
    /// </summary>
    /// <param name="context">The database context.</param>
    public RENRepository(DbContext context)
    {
        _context = context ?? throw new ArgumentNullException("context");
        _dbSet = context.Set<TEntity>();
    }

    #region Create

    /// <summary>
    ///     Inserts a single entity into the database.
    /// </summary>
    /// <param name="entity">The entity to insert.</param>
    public virtual void Insert(TEntity entity)
    {
        _dbSet.Add(entity);
    }

    /// <summary>
    ///     Inserts a single entity into the database asynchronously.
    /// </summary>
    /// <param name="entity">The entity to insert asynchronously.</param>
    /// <param name="cancellationToken">Optional cancellationToken.</param>
    /// <returns>A task representing the asynchronous operation.</returns>
    public virtual async Task InsertAsync(TEntity entity, CancellationToken cancellationToken = default)
    {
        cancellationToken.ThrowIfCancellationRequested();
        await _dbSet.AddAsync(entity, cancellationToken);
    }

    /// <summary>
    ///     Inserts a list of entities into the database.
    /// </summary>
    /// <param name="entities">The list of entities to insert.</param>
    public virtual void Insert(IEnumerable<TEntity> entities)
    {
        _dbSet.AddRange(entities);
    }

    /// <summary>
    ///     Inserts a list of entities into the database asynchronously.
    /// </summary>
    /// <param name="entities">The list of entities to insert asynchronously.</param>
    /// <param name="cancellationToken">Optional cancellationToken.</param>
    /// <returns>A task representing the asynchronous operation.</returns>
    public virtual async Task InsertAsync(IEnumerable<TEntity> entities, CancellationToken cancellationToken = default)
    {
        cancellationToken.ThrowIfCancellationRequested();
        await _dbSet.AddRangeAsync(entities, cancellationToken);
    }

    /// <summary>
    ///     Bulk inserts a list of entities into the repository.
    /// </summary>
    /// <param name="entities">The list of entities to insert.</param>
    public virtual void BulkInsert(IEnumerable<TEntity> entities, BulkConfig? bulkConfig = null)
    {
        bulkConfig ??= new BulkConfig();

        _context.BulkInsert(entities, bulkConfig);
    }

    /// <summary>
    ///     Bulk inserts a list of entities into the repository asynchronously.
    /// </summary>
    /// <param name="entities">The list of entities to insert asynchronously.</param>
    /// <param name="cancellationToken">Optional cancellationToken.</param>
    /// <returns>A task representing the asynchronous operation.</returns>
    public virtual async Task BulkInsertAsync(IEnumerable<TEntity> entities, BulkConfig? bulkConfig = null, CancellationToken cancellationToken = default)
    {
        bulkConfig ??= new BulkConfig();
        
        await _context.BulkInsertAsync(entities, bulkConfig, cancellationToken: cancellationToken);
    }

    #endregion

    #region Read

    /// <summary>
    ///     Gets a queryable collection of entities from the database.
    /// </summary>
    /// <param name="filter">An optional filter expression.</param>
    /// <param name="orderBy">An optional ordering expression.</param>
    /// <param name="include">An optional include expression.</param>
    /// <param name="isReadOnly">A flag indicating if the query is read-only.</param>
    /// <returns>A queryable collection of entities.</returns>
    public virtual IQueryable<TEntity> GetQueryable(Expression<Func<TEntity, bool>>? filter = null,
        Expression<Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>>? orderBy = null,
        Expression<Func<IQueryable<TEntity>, IQueryable<TEntity>>>? include = null, bool isReadOnly = false)
    {
        IQueryable<TEntity> query = _dbSet;

        if (include != null)
        {
            query = include.Compile().Invoke(query);
        }

        if (isReadOnly)
            query = query.AsNoTracking();

        if (filter != null)
            query = query.Where(filter);

        return orderBy != null ? orderBy.Compile().Invoke(query) : query;
    }

    /// <summary>
    ///     Gets a queryable collection of entities from the database asynchronously.
    /// </summary>
    /// <param name="filter">An optional filter expression.</param>
    /// <param name="orderBy">An optional ordering expression.</param>
    /// <param name="include">An optional include expression.</param>
    /// <param name="isReadOnly">A flag indicating if the query is read-only.</param>
    /// <param name="cancellationToken">Optional cancellationToken.</param>
    /// <returns>A task representing the queryable collection of entities.</returns>
    public virtual Task<IQueryable<TEntity>> GetQueryableAsync(Expression<Func<TEntity, bool>>? filter = null,
        Expression<Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>>? orderBy = null,
        Expression<Func<IQueryable<TEntity>, IQueryable<TEntity>>>? include = null, bool isReadOnly = false, CancellationToken cancellationToken = default)
    {
        return Task.Factory.StartNew(() =>
        {
            cancellationToken.ThrowIfCancellationRequested();

            IQueryable<TEntity> query = _dbSet;
            if (include != null)
            {
                query = include.Compile().Invoke(query);
            }

            if (isReadOnly)
                query = query.AsNoTracking();

            if (filter != null)
                query = query.Where(filter);

            return orderBy != null ? orderBy.Compile().Invoke(query) : query;
        }, cancellationToken);
    }

    /// <summary>
    ///     Gets a list of entities from the database.
    /// </summary>
    /// <param name="filter">An optional filter expression.</param>
    /// <param name="orderBy">An optional ordering expression.</param>
    /// <param name="include">An optional include expression.</param>
    /// <param name="isReadOnly">A flag indicating if the query is read-only.</param>
    /// <returns>A list of entities.</returns>
    public virtual List<TEntity> GetList(Expression<Func<TEntity, bool>>? filter = null,
        Expression<Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>>? orderBy = null,
        Expression<Func<IQueryable<TEntity>, IQueryable<TEntity>>>? include = null, bool isReadOnly = false)
    {
        return GetQueryable(filter, orderBy, include, isReadOnly).ToList();
    }

    /// <summary>
    ///     Gets a list of entities from the database asynchronously.
    /// </summary>
    /// <param name="filter">An optional filter expression.</param>
    /// <param name="orderBy">An optional ordering expression.</param>
    /// <param name="include">An optional include expression.</param>
    /// <param name="isReadOnly">A flag indicating if the query is read-only.</param>
    /// <param name="cancellationToken">Optional cancellationToken.</param>
    /// <returns>A task representing the list of entities.</returns>
    public virtual Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>>? filter = null,
        Expression<Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>>? orderBy = null,
        Expression<Func<IQueryable<TEntity>, IQueryable<TEntity>>>? include = null, bool isReadOnly = false, CancellationToken cancellationToken = default)
    {
        return GetQueryableAsync(filter, orderBy, include, isReadOnly, cancellationToken).Result.ToListAsync(cancellationToken);
    }

    /// <summary>
    ///     Gets a single entity from the database.
    /// </summary>
    /// <param name="filter">Required filter expression.</param>
    /// <param name="include">An optional include expression.</param>
    /// <param name="isReadOnly">A flag indicating if the query is read-only.</param>
    /// <returns>A single entity or null if not found.</returns>
    public virtual TEntity? GetSingle(Expression<Func<TEntity, bool>> filter,
        Expression<Func<IQueryable<TEntity>, IQueryable<TEntity>>>? include = null,
        bool isReadOnly = false)
    {
        return GetQueryable(filter, null, include, isReadOnly).SingleOrDefault();
    }

    /// <summary>
    ///     Gets a single entity from the database asynchronously.
    /// </summary>
    /// <param name="filter">Required filter expression.</param>
    /// <param name="include">An optional include expression.</param>
    /// <param name="isReadOnly">A flag indicating if the query is read-only.</param>
    /// <param name="cancellationToken">Optional cancellationToken.</param>
    /// <returns>A task representing the single entity or null if not found.</returns>
    public virtual Task<TEntity?> GetSingleAsync(Expression<Func<TEntity, bool>> filter,
        Expression<Func<IQueryable<TEntity>, IQueryable<TEntity>>>? include = null,
        bool isReadOnly = false,
        CancellationToken cancellationToken = default)
    {
        return GetQueryableAsync(filter, null, include, isReadOnly, cancellationToken).Result.SingleOrDefaultAsync(cancellationToken);
    }

    #endregion

    #region Update

    /// <summary>
    ///     Updates a single entity in the database.
    /// </summary>
    /// <param name="entity">The entity to update.</param>
    public virtual void Update(TEntity entity)
    {
        _context.Entry(entity).State = EntityState.Modified;
    }

    /// <summary>
    ///     Updates a single entity in the database asynchronously.
    /// </summary>
    /// <param name="entity">The entity to update asynchronously.</param>
    /// <param name="cancellationToken">Optional cancellationToken.</param>
    /// <returns>A task representing the asynchronous operation.</returns>
    public virtual Task UpdateAsync(TEntity entity, CancellationToken cancellationToken = default)
    {
        return Task.Factory.StartNew(() =>
        {
            cancellationToken.ThrowIfCancellationRequested();
            _context.Entry(entity).State = EntityState.Modified;
        }, cancellationToken);
    }

    /// <summary>
    ///     Bulk updates multiple entities in the repository.
    /// </summary>
    /// <param name="entity">The entities to update.</param>
    public virtual void BulkUpdate(IEnumerable<TEntity> entities, BulkConfig? bulkConfig = null)
    {
        bulkConfig ??= new BulkConfig();
        
        _context.BulkUpdate(entities, bulkConfig);
    }

    /// <summary>
    ///     Bulk updates multiple entities in the repository asynchronously.
    /// </summary>
    /// <param name="entity">The entities to update asynchronously.</param>
    /// <param name="cancellationToken">Optional cancellationToken.</param>
    /// <returns>A task representing the asynchronous operation.</returns>
    public virtual async Task BulkUpdateAsync(IEnumerable<TEntity> entities, BulkConfig? bulkConfig = null, CancellationToken cancellationToken = default)
    {
        bulkConfig ??= new BulkConfig();
        
        await _context.BulkUpdateAsync(entities, bulkConfig, cancellationToken: cancellationToken);
    }

    #endregion

    #region Delete

    /// <summary>
    ///     Deletes a single entity from the database.
    /// </summary>
    /// <param name="entity">The entity to delete.</param>
    public virtual void Delete(TEntity entity)
    {
        _dbSet.Remove(entity);
    }

    /// <summary>
    ///     Deletes a single entity from the database asynchronously.
    /// </summary>
    /// <param name="entity">The entity to delete asynchronously.</param>
    /// <param name="cancellationToken">Optional cancellationToken.</param>
    /// <returns>A task representing the asynchronous operation.</returns>
    public virtual Task DeleteAsync(TEntity entity, CancellationToken cancellationToken = default)
    {
        return Task.Factory.StartNew(() =>
        {
            cancellationToken.ThrowIfCancellationRequested();
            return _dbSet.Remove(entity);
        }, cancellationToken);
    }

    /// <summary>
    ///     Deletes a list of entities from the database.
    /// </summary>
    /// <param name="entities">The list of entities to delete.</param>
    public virtual void Delete(IEnumerable<TEntity> entities)
    {
        _dbSet.RemoveRange(entities);
    }

    /// <summary>
    ///     Deletes a list of entities from the database asynchronously.
    /// </summary>
    /// <param name="entities">The list of entities to delete asynchronously.</param>
    /// <param name="cancellationToken">Optional cancellationToken.</param>
    /// <returns>A task representing the asynchronous operation.</returns>
    public virtual Task DeleteAsync(IEnumerable<TEntity> entities, CancellationToken cancellationToken = default)
    {
        return Task.Factory.StartNew(() =>
        {
            cancellationToken.ThrowIfCancellationRequested();
            _dbSet.RemoveRange(entities);
        }, cancellationToken);
    }

    /// <summary>
    ///     Bulk deletes a list of entities from the repository.
    /// </summary>
    /// <param name="entities">The list of entities to delete asynchronously.</param>{{}
    public virtual void BulkDelete(IEnumerable<TEntity> entities, BulkConfig? bulkConfig = null)
    {
        bulkConfig ??= new BulkConfig();
        
        _context.BulkDelete(entities, bulkConfig);
    }

    /// <summary>
    ///     Bulk deletes a list of entities from the repository asynchronously.
    /// </summary>
    /// <param name="entities">The list of entities to delete asynchronously.</param>
    /// <param name="cancellationToken">Optional cancellationToken.</param>
    /// <returns>A task representing the asynchronous operation.</returns>
    public virtual async Task BulkDeleteAsync(IEnumerable<TEntity> entities, BulkConfig? bulkConfig = null, CancellationToken cancellationToken = default)
    {
        bulkConfig ??= new BulkConfig();
        
        await _context.BulkDeleteAsync(entities, bulkConfig, cancellationToken: cancellationToken);
    }

    #endregion
}

Here, you can see all methods are defined as virtual which allows you to override them if necessary according to your needs. To use this pre-defined methods, you don't need to register them in Program.cs file since they can be produced within the GetRENRepository function in RENUnitOfWork

You can use RENRepositories like this:

public class HomeController : ControllerBase
{
    private readonly IRENRepository<User> _userRepository;
    
    public HomeController(IMyUnitOfWork<RENDbContext> uow)
    {
        _userRepository = _uow.GetRENRepository<User>();
    }
    
    [HttpGet, Route("GetUsers")]
    public async Task<IActionResult> SideIndex()
    {
        var users = await _userRepository.GetListAsync();

        return Ok(users);
    }
}

Last updated