using DigitalData.Core.Abstractions; using DigitalData.Core.Application; using DigitalData.Core.Application.Interfaces.Repository; using Microsoft.EntityFrameworkCore; namespace DigitalData.Core.Infrastructure { /// /// Provides a generic implementation for CRUD (Create, Read, Update, Delete) operations within a given DbContext. /// /// The entity type for which the repository is created. Must be a class. /// The type of the entity's identifier. /// The DbContext type associated with the entity. /// /// This repository abstracts the common database operations, offering an asynchronous API to work with the entity's data. /// It leverages the EF Core's DbContext and DbSet to perform these operations. /// public class CRUDRepository : ICRUDRepository where TEntity : class where TDbContext : DbContext { protected readonly TDbContext _dbContext; protected readonly DbSet _dbSet; /// /// Initializes a new instance of the CRUDRepository with the specified DbContext. /// /// The DbContext instance to be used by the repository. /// The DbSet instance to be used by the repository. public CRUDRepository(TDbContext dbContext, DbSet dbSet) { _dbContext = dbContext; _dbSet = dbSet; } /// /// Asynchronously creates a new entity in the database. /// /// The entity to be added. /// The created entity, or null if the entity cannot be added public virtual async Task CreateAsync(TEntity entity) { await _dbSet.AddAsync(entity); await _dbContext.SaveChangesAsync(); return entity; } /// /// Asynchronously retrieves an entity by its identifier. /// /// The identifier of the entity to find. /// The entity found, or null if no entity is found with the specified identifier. public virtual async Task ReadByIdAsync(TId id) => await _dbSet.FindAsync(id); /// /// Retrieves all entities of type from the database. /// /// /// This method returns an of all entities in the database. /// The result is not tracked by the context, which improves performance when you only need to read data without making modifications. /// /// An containing all entities of type . protected virtual IQueryable ReadOnly() => _dbSet.AsNoTracking(); /// /// Asynchronously retrieves all entities of type TEntity. /// /// An enumerable of all entities in the database. public virtual async Task> ReadAllAsync() => await ReadOnly().ToListAsync(); /// /// Asynchronously updates an existing entity in the repository. /// /// The entity to be updated. This entity should already exist in the repository. /// A task that represents the asynchronous operation. The task result contains a boolean value that indicates whether the update operation was successful. Returns true if one or more entities were successfully updated; otherwise, false. public virtual async Task UpdateAsync(TEntity entity) { _dbContext.Entry(entity).State = EntityState.Modified; var results = await _dbContext.SaveChangesAsync(); return results > 0; } /// /// Asynchronously deletes an entity from the database. /// /// The entity to be deleted. /// If entity is deleted, return true othwerwise return false. public virtual async Task DeleteAsync(TEntity entity) { _dbSet.Remove(entity); var result = await _dbContext.SaveChangesAsync(); return result > 0; } /// /// Asynchronously counts all entities in the repository. /// /// The total number of entities in the repository. public virtual async Task CountAsync() => await _dbSet.CountAsync(); /// /// Asynchronously counts the number of entities in the repository that match a specific identifier. /// /// The identifier of the entities to count. /// The number of entities with the specified identifier. /// /// This method provides a count of entities in the database that match the given identifier. /// If there are multiple entities with the same identifier, they will all be counted. /// The default implementation assumes that the identifier is unique for each entity. /// public virtual async Task CountAsync(TId id) => await _dbSet.Where(e => e.GetId().Equals(id)).CountAsync(); } }