< Summary

Information
Class: CoWorkingApp.Core.Application.Abstracts.ServiceGeneric<T1, T2, T3, T4>
Assembly: CoWorkingApp.Core
File(s): H:\Vicentico\Proyectos\CoWorkingApp Project\CoWorkingApp\CoWorkingApp.Core\Application\Abstracts\ServiceGeneric.cs
Line coverage
100%
Covered lines: 113
Uncovered lines: 0
Coverable lines: 113
Total lines: 296
Line coverage: 100%
Branch coverage
100%
Covered branches: 24
Total branches: 24
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity Line coverage
.ctor(...)100%4100%
HandleException(...)100%1100%
GetAllAsync()100%2100%
GetByIdAsync()100%2100%
CreateAsync()100%6100%
UpdateAsync()100%8100%
DeleteAsync()100%4100%

File(s)

H:\Vicentico\Proyectos\CoWorkingApp Project\CoWorkingApp\CoWorkingApp.Core\Application\Abstracts\ServiceGeneric.cs

#LineLine coverage
 1using CoWorkingApp.Core.Application.Contracts.Adapters;
 2using CoWorkingApp.Core.Application.Contracts.Repositories;
 3using CoWorkingApp.Core.Application.Contracts.Requests;
 4using CoWorkingApp.Core.Application.Contracts.Services;
 5using System.ComponentModel.DataAnnotations;
 6
 7namespace CoWorkingApp.Core.Application.Abstracts
 8{
 9    /// <summary>
 10    /// Clase abstracta que proporciona una implementación genérica para servicios que manejan operaciones CRUD básicas.
 11    /// </summary>
 12    /// <typeparam name="TRepository">Tipo de repositorio asociado al servicio.</typeparam>
 13    /// <typeparam name="TEntity">Tipo de entidad que se manejará.</typeparam>
 14    /// <typeparam name="TRequest">Tipo de objeto de solicitud.</typeparam>
 15    /// <typeparam name="TResponse">Tipo de objeto de respuesta.</typeparam>
 16    public abstract class ServiceGeneric<TRepository, TEntity, TRequest, TResponse> : IService<TRequest, TResponse>
 17        where TRepository : IRepository<TEntity>
 18        where TEntity : EntityBase
 19        where TRequest : IRequest
 20        where TResponse : ResponseMessage, new()
 21    {
 22        protected readonly TRepository _repository;
 23        protected readonly IMapperAdapter _mapper;
 24
 25        /// <summary>
 26        /// Constructor de la clase ServiceGeneric.
 27        /// </summary>
 28        /// <param name="repository">El repositorio asociado al servicio.</param>
 29        /// <param name="mapper">El adaptador de mapeo utilizado para mapear entre tipos de entidades y DTO.</param>
 18130        protected ServiceGeneric(TRepository repository, IMapperAdapter mapper)
 18131        {
 18132            _repository = repository ?? throw new ArgumentNullException(nameof(repository));
 17833            _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
 17534        }
 35
 36        /// <summary>
 37        /// Maneja las excepciones y construye una respuesta de error coherente.
 38        /// </summary>
 39        /// <param name="ex">La excepción que se va a manejar.</param>
 40        /// <returns>Un objeto de respuesta que representa el error.</returns>
 41        protected TResponse HandleException(Exception ex)
 12342        {
 12343            return ResponseMessage.HandleException<TResponse>(ex);
 12344        }
 45
 46        // Implementación de métodos de la interfaz IService
 47
 48        /// <summary>
 49        /// Obtiene todas las entidades de manera asincrónica.
 50        /// </summary>
 51        /// <returns>Una colección de objetos de respuesta.</returns>
 52        public virtual async Task<IEnumerable<TResponse>> GetAllAsync()
 953        {
 54            try
 955            {
 56                // Obtener todas las entidades del repositorio
 957                var entities = await _repository.GetAllAsync();
 58
 59                // Mapear las entidades a objetos de respuesta y retornarlos
 660                var responses = _mapper.Map<IEnumerable<TEntity>, IEnumerable<TResponse>>(entities).ToList();
 1261                responses.ForEach(res => res.Success = true);
 662                return responses;
 63            }
 364            catch (Exception ex)
 365            {
 66                // Manejar excepciones inesperadas y generar una respuesta de error
 367                return new List<TResponse> { HandleException(ex) };
 68            }
 969        }
 70
 71        /// <summary>
 72        /// Obtiene una entidad por su ID de manera asincrónica.
 73        /// </summary>
 74        /// <param name="id">El ID de la entidad.</param>
 75        /// <returns>Un objeto de respuesta.</returns>
 76        public virtual async Task<TResponse> GetByIdAsync(Guid id)
 977        {
 78            try
 979            {
 80                // Buscar la entidad por su ID en el repositorio. Si no, lanzar una excepción
 981                var entity = await _repository.GetByIdAsync(id) ?? throw new ArgumentException($"Entity with id {id} not
 82
 83                // Mapear la entidad a un objeto de respuesta y retornarlo
 384                var response = _mapper.Map<TEntity, TResponse>(entity);
 385                response.Success = true;
 386                return response;
 87            }
 388            catch (ArgumentException ex)
 389            {
 90                // Manejar la excepción de entidad no encontrada y generar una respuesta de error
 391                return HandleException(ex);
 92            }
 393            catch (Exception ex)
 394            {
 95                // Manejar excepciones inesperadas y generar una respuesta de error
 396                return HandleException(ex);
 97            }
 998        }
 99
 100        /// <summary>
 101        /// Crea una nueva entidad de manera asincrónica.
 102        /// </summary>
 103        /// <param name="request">El objeto de solicitud.</param>
 104        /// <returns>Un objeto de respuesta.</returns>
 105        public virtual async Task<TResponse> CreateAsync(TRequest request)
 32106        {
 107            try
 32108            {
 109                // Verificar si la solicitud es nula
 32110                if (request is null)
 3111                {
 112                    // Si la solicitud es nula, lanzar una excepción
 3113                    throw new ArgumentNullException("The request object cannot be null");
 114                }
 115
 116                // Mapear la solicitud a una entidad
 29117                var entity = _mapper.Map<TRequest, TEntity>(request);
 118
 119                // Validar la entidad
 26120                if (!IsValid(entity))
 18121                {
 122                    // Si la entidad no es válida, lanzar una excepción
 18123                    throw new ValidationException("Argument is invalid.");
 124                }
 125
 126                // Agregar la entidad al repositorio
 8127                var added = await _repository.AddAsync(entity);
 128
 129                // Verificar si la entidad fue agregada correctamente
 8130                if (!added)
 3131                {
 132                    // Si la entidad no fue agregada, lanzar una excepción
 3133                    throw new InvalidOperationException("The entity could not be added.");
 134                }
 135
 136                // Mapear la entidad a un objeto de respuesta y retornarlo
 5137                var response = _mapper.Map<TEntity, TResponse>(entity);
 5138                response.Success = true;
 5139                return response;
 140            }
 3141            catch (ArgumentNullException ex)
 3142            {
 143                // Manejar la excepción de argumento nulo y generar una respuesta de error
 3144                return HandleException(ex);
 145            }
 18146            catch (ValidationException ex)
 18147            {
 148                // Manejar la excepción de validación y generar una respuesta de error
 18149                return HandleException(ex);
 150            }
 3151            catch (InvalidOperationException ex)
 3152            {
 153                // Manejar la excepción de operación no válida y generar una respuesta de error
 3154                return HandleException(ex);
 155            }
 3156            catch (Exception ex)
 3157            {
 158                // Manejar excepciones inesperadas y generar una respuesta de error
 3159                return HandleException(ex);
 160            }
 32161        }
 162
 163        /// <summary>
 164        /// ACTualiza una entidad existente de manera asincrónica.
 165        /// </summary>
 166        /// <param name="id">El ID de la entidad.</param>
 167        /// <param name="request">El objeto de solicitud.</param>
 168        /// <returns>Un objeto de respuesta.</returns>
 169        public virtual async Task<TResponse> UpdateAsync(Guid id, TRequest request)
 50170        {
 171            try
 50172            {
 173                // Verificar si la solicitud es nula
 50174                if (request is null)
 3175                {
 176                    // Si la solicitud es nula, lanzar una excepción
 3177                    throw new ArgumentNullException("The request object cannot be null");
 178                }
 179
 180                // Obtener la entidad existente por su ID. Si no, lanzar una excepción
 47181                var existingEntity = await _repository.GetByIdAsync(id) ?? throw new ArgumentException($"Entity with id 
 182
 183                // ACTualizar las propiedades de la entidad existente con los valores de la solicitud
 44184                var updatedEntity = UpdateProperties(existingEntity, request);
 185
 186                // Validar la entidad actualizada
 44187                if (!IsValid(updatedEntity))
 18188                {
 189                    // Si la entidad no es válida, lanzar una excepción
 18190                    throw new ValidationException("Argument is invalid.");
 191                }
 192
 193                // ACTualizar la entidad en el repositorio
 26194                bool updated = await _repository.UpdateAsync(updatedEntity);
 195
 196                // Verificar si la entidad fue actualizada correctamente
 26197                if (!updated)
 5198                {
 199                    // Si la entidad no fue actualizada, lanzar una excepción
 5200                    throw new InvalidOperationException("The entity could not be updated.");
 201                }
 202
 203                // Mapear la entidad actualizada a un objeto de respuesta y retornarlo
 21204                var response = _mapper.Map<TEntity, TResponse>(updatedEntity);
 16205                response.Success = true;
 16206                return response;
 207            }
 3208            catch (ArgumentNullException ex)
 3209            {
 210                // Manejar la excepción de argumento nulo y generar una respuesta de error
 3211                return HandleException(ex);
 212            }
 3213            catch (ArgumentException ex)
 3214            {
 215                // Manejar la excepción de argumento inválido y generar una respuesta de error
 3216                return HandleException(ex);
 217            }
 18218            catch (ValidationException ex)
 18219            {
 220                // Manejar la excepción de validación y generar una respuesta de error
 18221                return HandleException(ex);
 222            }
 5223            catch (InvalidOperationException ex)
 5224            {
 225                // Manejar la excepción de operación no válida y generar una respuesta de error
 5226                return HandleException(ex);
 227            }
 5228            catch (Exception ex)
 5229            {
 230                // Manejar excepciones inesperadas y generar una respuesta de error
 5231                return HandleException(ex);
 232            }
 50233        }
 234
 235        /// <summary>
 236        /// Elimina una entidad por su ID de manera asincrónica.
 237        /// </summary>
 238        /// <param name="id">El ID de la entidad.</param>
 239        /// <returns>Un objeto de respuesta.</returns>
 240        public virtual async Task<TResponse> DeleteAsync(Guid id)
 24241        {
 242            try
 24243            {
 244                // Obtener la entidad por su ID. Si no, lanzar una excepción
 24245                var entity = await _repository.GetByIdAsync(id) ?? throw new ArgumentNullException($"Entity with id {id}
 246
 247                // Eliminar la entidad del repositorio
 21248                var deleted = await _repository.RemoveAsync(entity);
 249
 250                // Verificar si la entidad fue eliminada correctamente
 21251                if (!deleted)
 7252                {
 253                    // Si la entidad no fue eliminada, lanzar una excepción
 7254                    throw new InvalidOperationException("The entity could not be deleted.");
 255                }
 256
 257                // Mapear la entidad eliminada a un objeto de respuesta y retornarlo
 14258                var response = _mapper.Map<TEntity, TResponse>(entity);
 7259                response.Success = true;
 7260                return response;
 261            }
 3262            catch (ArgumentNullException ex)
 3263            {
 264                // Manejar la excepción de argumento nulo y generar una respuesta de error
 3265                return HandleException(ex);
 266            }
 7267            catch (InvalidOperationException ex)
 7268            {
 269                // Manejar la excepción de operación no válida y generar una respuesta de error
 7270                return HandleException(ex);
 271            }
 7272            catch (Exception ex)
 7273            {
 274                // Manejar excepciones inesperadas y generar una respuesta de error
 7275                return HandleException(ex);
 276            }
 24277        }
 278
 279        // Métodos abstractos que deben ser implementados por las clases derivadas
 280
 281        /// <summary>
 282        /// ACTualiza las propiedades de una entidad existente con los valores de una nueva entidad.
 283        /// </summary>
 284        /// <param name="existingEntity">La entidad existente que se va a actualizar.</param>
 285        /// <param name="request">La entidad con los nuevos valores.</param>
 286        /// <returns>La entidad actualizada.</returns>
 287        protected abstract TEntity UpdateProperties(TEntity existingEntity, TRequest request);
 288
 289        /// <summary>
 290        /// Verifica si una entidad es válida.
 291        /// </summary>
 292        /// <param name="entity">La entidad que se va a validar.</param>
 293        /// <returns>True si la entidad es válida, de lo contrario False.</returns>
 294        protected abstract bool IsValid(TEntity entity);
 295    }
 296}