Skip to content

Commit

Permalink
Added generic repository
Browse files Browse the repository at this point in the history
  • Loading branch information
goodtocode committed Jul 9, 2023
1 parent 5947e47 commit aa044bb
Show file tree
Hide file tree
Showing 22 changed files with 264 additions and 66 deletions.
13 changes: 13 additions & 0 deletions src/Subjects/Common.Persistence/Cache/CacheConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Goodtocode.Common.Persistence.Cache;

/// <summary>
/// "CacheConfiguration": {
/// "AbsoluteExpirationInHours": 1,
/// "SlidingExpirationInMinutes": 30
/// }
/// </summary>
public class CacheConfiguration
{
public int AbsoluteExpirationInHours { get; set; }
public int SlidingExpirationInMinutes { get; set; }
}
7 changes: 7 additions & 0 deletions src/Subjects/Common.Persistence/Cache/CacheTypes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Goodtocode.Common.Persistence.Cache;

public enum CacheTypes
{
Redis,
Memory
}
8 changes: 8 additions & 0 deletions src/Subjects/Common.Persistence/Cache/ICacheService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Goodtocode.Common.Persistence.Cache;

public interface ICacheService
{
bool TryGet<T>(string cacheKey, out T value);
T Set<T>(string cacheKey, T value);
void Remove(string cacheKey);
}
39 changes: 39 additions & 0 deletions src/Subjects/Common.Persistence/Cache/MemoryCacheService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;

namespace Goodtocode.Common.Persistence.Cache;

public class MemoryCacheService : ICacheService
{
private readonly IMemoryCache _memoryCache;
private readonly CacheConfiguration _cacheConfig;
private readonly MemoryCacheEntryOptions _cacheOptions;
public MemoryCacheService(IMemoryCache memoryCache, IOptions<CacheConfiguration> cacheConfig)

Check warning on line 11 in src/Subjects/Common.Persistence/Cache/MemoryCacheService.cs

View workflow job for this annotation

GitHub Actions / Build, Test and Deploy .NET (7.0.x)

Non-nullable field '_cacheConfig' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.

Check warning on line 11 in src/Subjects/Common.Persistence/Cache/MemoryCacheService.cs

View workflow job for this annotation

GitHub Actions / Build, Test and Deploy .NET (7.0.x)

Non-nullable field '_cacheOptions' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.
{
_memoryCache = memoryCache;
_cacheConfig = cacheConfig.Value;
if (_cacheConfig != null)
{
_cacheOptions = new MemoryCacheEntryOptions
{
AbsoluteExpiration = DateTime.Now.AddHours(_cacheConfig.AbsoluteExpirationInHours),
Priority = CacheItemPriority.High,
SlidingExpiration = TimeSpan.FromMinutes(_cacheConfig.SlidingExpirationInMinutes)
};
}
}
public bool TryGet<T>(string cacheKey, out T value)
{
_memoryCache.TryGetValue(cacheKey, out value);

Check warning on line 27 in src/Subjects/Common.Persistence/Cache/MemoryCacheService.cs

View workflow job for this annotation

GitHub Actions / Build, Test and Deploy .NET (7.0.x)

Possible null reference assignment.
if (value == null) return false;
else return true;
}
public T Set<T>(string cacheKey, T value)
{
return _memoryCache.Set(cacheKey, value, _cacheOptions);
}
public void Remove(string cacheKey)
{
_memoryCache.Remove(cacheKey);
}
}
17 changes: 17 additions & 0 deletions src/Subjects/Common.Persistence/Cache/RedisCacheService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Goodtocode.Common.Persistence.Cache;

public class RedisCacheService : ICacheService
{
public void Remove(string cacheKey)
{
throw new NotImplementedException();
}
public T Set<T>(string cacheKey, T value)
{
throw new NotImplementedException();
}
public bool TryGet<T>(string cacheKey, out T value)
{
throw new NotImplementedException();
}
}
20 changes: 20 additions & 0 deletions src/Subjects/Common.Persistence/Common.Persistence.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<RootNamespace>Goodtocode.Common.Persistence</RootNamespace>
<AssemblyName>Goodtocode.Common.Persistence</AssemblyName>
<Version>1.0.0</Version>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.8" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="7.0.1" />
</ItemGroup>
</Project>
29 changes: 29 additions & 0 deletions src/Subjects/Common.Persistence/ConfigureServices.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Goodtocode.Common.Persistence.Cache;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace Goodtocode.Common.Persistence;

public static class ConfigureServices
{
public static IServiceCollection AddInfrastructureServices(this IServiceCollection services,
IConfiguration configuration)
{
services.Configure<CacheConfiguration>(options => { configuration.GetSection("CacheConfiguration"); });
//For In-Memory Caching
services.AddMemoryCache();
services.AddTransient<MemoryCacheService>();
services.AddTransient<RedisCacheService>();
services.AddTransient<Func<CacheTypes, ICacheService>>(serviceProvider => key =>
{
return key switch

Check warning on line 19 in src/Subjects/Common.Persistence/ConfigureServices.cs

View workflow job for this annotation

GitHub Actions / Build, Test and Deploy .NET (7.0.x)

Possible null reference return.
{
CacheTypes.Memory => serviceProvider.GetService<MemoryCacheService>(),
CacheTypes.Redis => serviceProvider.GetService<RedisCacheService>(),
_ => serviceProvider.GetService<MemoryCacheService>(),
};
});

return services;
}
}
55 changes: 55 additions & 0 deletions src/Subjects/Common.Persistence/Repository/GenericRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using Goodtocode.Common.Persistence.Cache;
using Microsoft.EntityFrameworkCore;

namespace Goodtocode.Common.Persistence.Repository;

public class GenericRepository<T> : IGenericRepository<T> where T : class
{
private readonly static CacheTypes CacheTypes = CacheTypes.Memory;
private readonly string cacheKey = $"{typeof(T)}";
private readonly DbContext _dbContext;
private readonly Func<CacheTypes, ICacheService> _cacheService;
public GenericRepository(DbContext dbContext, Func<CacheTypes, ICacheService> cacheService)
{
_dbContext = dbContext;
_cacheService = cacheService;
}
public virtual async Task<T> GetByIdAsync(int id)
{
return await _dbContext.Set<T>().FindAsync(id);

Check warning on line 19 in src/Subjects/Common.Persistence/Repository/GenericRepository.cs

View workflow job for this annotation

GitHub Actions / Build, Test and Deploy .NET (7.0.x)

Possible null reference return.
}
public async Task<IReadOnlyList<T>> GetAllAsync()
{
if (!_cacheService(CacheTypes).TryGet(cacheKey, out IReadOnlyList<T> cachedList))
{
cachedList = await _dbContext.Set<T>().ToListAsync();
_cacheService(CacheTypes).Set(cacheKey, cachedList);
}
return cachedList;
}
public async Task<T> AddAsync(T entity)
{
await _dbContext.Set<T>().AddAsync(entity);
await _dbContext.SaveChangesAsync();
await RefreshCache();
return entity;
}
public async Task UpdateAsync(T entity)
{
_dbContext.Entry(entity).State = EntityState.Modified;
await _dbContext.SaveChangesAsync();
await RefreshCache();
}
public async Task DeleteAsync(T entity)
{
_dbContext.Set<T>().Remove(entity);
await _dbContext.SaveChangesAsync();
await RefreshCache();
}
public async Task RefreshCache()
{
_cacheService(CacheTypes).Remove(cacheKey);
var cachedList = await _dbContext.Set<T>().ToListAsync();
_cacheService(CacheTypes).Set(cacheKey, cachedList);
}
}
10 changes: 10 additions & 0 deletions src/Subjects/Common.Persistence/Repository/IGenericRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace Goodtocode.Common.Persistence.Repository;

public interface IGenericRepository<T> where T : class
{
Task<T> GetByIdAsync(int id);
Task<IReadOnlyList<T>> GetAllAsync();
Task<T> AddAsync(T entity);
Task UpdateAsync(T entity);
Task DeleteAsync(T entity);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,11 @@ public class GetBusinessByKeyQuery : IRequest<BusinessEntity>

public class GetBusinessByKeyQueryHandler : IRequestHandler<GetBusinessByKeyQuery, BusinessEntity?>
{
private readonly IMapper _mapper;
private readonly IBusinessRepo _userBusinessRepo;

public GetBusinessByKeyQueryHandler(IBusinessRepo userBusinessRepo, IMapper mapper)
public GetBusinessByKeyQueryHandler(IBusinessRepo userBusinessRepo)
{
_userBusinessRepo = userBusinessRepo;
_mapper = mapper;
}

public async Task<BusinessEntity?> Handle(GetBusinessByKeyQuery request,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ namespace Goodtocode.Subjects.Application;
public class GetBusinessesAllQuery : IRequest<PagedResult<BusinessEntity>>
{
public string BusinessName { get; set; } = string.Empty;
public int Page { get; set; } = 1;
public int Results { get; set; } = 20;
public int PageNumber { get; set; } = 1;
public int PageSize { get; set; } = 20;
}

public class GetBusinessesAllQueryHandler : IRequestHandler<GetBusinessesAllQuery, PagedResult<BusinessEntity>>
Expand All @@ -24,7 +24,7 @@ public GetBusinessesAllQueryHandler(IBusinessRepo userBusinessesRepo)
CancellationToken cancellationToken)
{
var businesses =
await _userBusinessesRepo.GetBusinessesAllAsync(request.BusinessName, request.Page, request.Results,
await _userBusinessesRepo.GetBusinessesAllAsync(request.BusinessName, request.PageNumber, request.PageSize,
cancellationToken);

return businesses.GetValueOrDefault();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public class GetBusinessesAllQueryValidator : AbstractValidator<GetBusinessesAll
public GetBusinessesAllQueryValidator()
{
RuleFor(x => x.BusinessName).NotEmpty();
RuleFor(x => x.Results).GreaterThan(0);
RuleFor(x => x.Page).GreaterThan(0);
RuleFor(x => x.PageSize).GreaterThan(0);
RuleFor(x => x.PageNumber).GreaterThan(0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ namespace Goodtocode.Subjects.Application;
public class GetBusinessesByNameQuery : IRequest<PagedResult<BusinessEntity>>
{
public string BusinessName { get; set; } = string.Empty;
public int Page { get; set; } = 1;
public int Results { get; set; } = 20;
public int PageNumber { get; set; } = 1;
public int PageSize { get; set; } = 20;
}

public class GetBusinessesByNameQueryHandler : IRequestHandler<GetBusinessesByNameQuery, PagedResult<BusinessEntity>>
Expand All @@ -24,7 +24,7 @@ public GetBusinessesByNameQueryHandler(IBusinessRepo userBusinessesRepo)
CancellationToken cancellationToken)
{
var businesses =
await _userBusinessesRepo.GetBusinessesByNameAsync(request.BusinessName, request.Page, request.Results,
await _userBusinessesRepo.GetBusinessesByNameAsync(request.BusinessName, request.PageNumber, request.PageSize,
cancellationToken);

return businesses.GetValueOrDefault();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public class GetBusinessesByNameQueryValidator : AbstractValidator<GetBusinesses
public GetBusinessesByNameQueryValidator()
{
RuleFor(x => x.BusinessName).NotEmpty();
RuleFor(x => x.Results).GreaterThan(0);
RuleFor(x => x.Page).GreaterThan(0);
RuleFor(x => x.PageSize).GreaterThan(0);
RuleFor(x => x.PageNumber).GreaterThan(0);
}
}
2 changes: 1 addition & 1 deletion src/Subjects/Core.Application/Interfaces/IBusinessRepo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace Goodtocode.Subjects.Application;

public interface IBusinessRepo : IDisposable
public interface IBusinessRepo
{
Task<Result<BusinessEntity?>> GetBusinessByKeyAsync(Guid businessKey,
CancellationToken cancellationToken);
Expand Down
46 changes: 23 additions & 23 deletions src/Subjects/Core.Application/Interfaces/ISubjectsDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,30 @@

namespace Goodtocode.Subjects.Application;

public interface ISubjectsDbContext : IDisposable
public interface ISubjectsDbContext
{
DbSet<BusinessEntity> Business { get; }
//DbSet<Detail> Detail { get; set; }
//DbSet<DetailType> DetailType { get; set; }
//DbSet<Associate> Associate { get; set; }
//DbSet<AssociateDetail> AssociateDetail { get; set; }
//DbSet<AssociateOption> AssociateOption { get; set; }
//DbSet<Gender> Gender { get; set; }
//DbSet<Government> Government { get; set; }
//DbSet<Item> Item { get; set; }
//DbSet<ItemGroup> ItemGroup { get; set; }
//DbSet<ItemType> ItemType { get; set; }
//DbSet<Option> Option { get; set; }
//DbSet<OptionGroup> OptionGroup { get; set; }
//DbSet<Person> Person { get; set; }
//DbSet<Resource> Resource { get; set; }
//DbSet<ResourceItem> ResourceItem { get; set; }
//DbSet<ResourcePerson> ResourcePerson { get; set; }
//DbSet<ResourceType> ResourceType { get; set; }
//DbSet<Venture> Venture { get; set; }
//DbSet<VentureDetail> VentureDetail { get; set; }
//DbSet<VentureAssociateOption> VentureAssociateOption { get; set; }
//DbSet<VentureOption> VentureOption { get; set; }
//DbSet<VentureResource> VentureResource { get; set; }
//DbSet<Detail> Detail { get; }
//DbSet<DetailType> DetailType { get; }
//DbSet<Associate> Associate { get; }
//DbSet<AssociateDetail> AssociateDetail { get; }
//DbSet<AssociateOption> AssociateOption { get; }
//DbSet<Gender> Gender { get; }
//DbSet<Government> Government { get; }
//DbSet<Item> Item { get; }
//DbSet<ItemGroup> ItemGroup { get; }
//DbSet<ItemType> ItemType { get; }
//DbSet<Option> Option { get; }
//DbSet<OptionGroup> OptionGroup { get; }
//DbSet<Person> Person { get; }
//DbSet<Resource> Resource { get; }
//DbSet<ResourceItem> ResourceItem { get; }
//DbSet<ResourcePerson> ResourcePerson { get; }
//DbSet<ResourceType> ResourceType { get; }
//DbSet<Venture> Venture { get; }
//DbSet<VentureDetail> VentureDetail { get; }
//DbSet<VentureAssociateOption> VentureAssociateOption { get; }
//DbSet<VentureOption> VentureOption { get; }
//DbSet<VentureResource> VentureResource { get; }
Task<int> SaveChangesAsync(CancellationToken cancellationToken);
}
Loading

0 comments on commit aa044bb

Please sign in to comment.