-
Notifications
You must be signed in to change notification settings - Fork 0
feat(34): implement repository and unit of work patterns with EF Core… #36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,21 +1,68 @@ | ||
| Microsoft Visual Studio Solution File, Format Version 12.00 | ||
| # Visual Studio Version 17 | ||
| VisualStudioVersion = 17.0.31903.59 | ||
| MinimumVisualStudioVersion = 10.0.40219.1 | ||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microservice", "src\Api\Microservice.csproj", "{AC3F0F1B-31CD-47D4-953F-FC970261B9FB}" | ||
| EndProject | ||
| Global | ||
| GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
| Debug|Any CPU = Debug|Any CPU | ||
| Release|Any CPU = Release|Any CPU | ||
| EndGlobalSection | ||
| GlobalSection(SolutionProperties) = preSolution | ||
| HideSolutionNode = FALSE | ||
| EndGlobalSection | ||
| GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
| {AC3F0F1B-31CD-47D4-953F-FC970261B9FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
| {AC3F0F1B-31CD-47D4-953F-FC970261B9FB}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
| {AC3F0F1B-31CD-47D4-953F-FC970261B9FB}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
| {AC3F0F1B-31CD-47D4-953F-FC970261B9FB}.Release|Any CPU.Build.0 = Release|Any CPU | ||
| EndGlobalSection | ||
| EndGlobal | ||
| | ||
| Microsoft Visual Studio Solution File, Format Version 12.00 | ||
| # Visual Studio Version 17 | ||
| VisualStudioVersion = 17.0.31903.59 | ||
| MinimumVisualStudioVersion = 10.0.40219.1 | ||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microservice", "src\Api\Microservice.csproj", "{AC3F0F1B-31CD-47D4-953F-FC970261B9FB}" | ||
| EndProject | ||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}" | ||
| EndProject | ||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Infra", "src\Infra\Infra.csproj", "{73439EED-AE10-430D-99E5-2BD7E922BA8E}" | ||
| EndProject | ||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Domain", "src\Domain\Domain.csproj", "{A664D19C-0BDC-4B5F-AD31-C7BA0217DD22}" | ||
| EndProject | ||
| Global | ||
| GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
| Debug|Any CPU = Debug|Any CPU | ||
| Debug|x64 = Debug|x64 | ||
| Debug|x86 = Debug|x86 | ||
| Release|Any CPU = Release|Any CPU | ||
| Release|x64 = Release|x64 | ||
| Release|x86 = Release|x86 | ||
| EndGlobalSection | ||
| GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
| {AC3F0F1B-31CD-47D4-953F-FC970261B9FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
| {AC3F0F1B-31CD-47D4-953F-FC970261B9FB}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
| {AC3F0F1B-31CD-47D4-953F-FC970261B9FB}.Debug|x64.ActiveCfg = Debug|Any CPU | ||
| {AC3F0F1B-31CD-47D4-953F-FC970261B9FB}.Debug|x64.Build.0 = Debug|Any CPU | ||
| {AC3F0F1B-31CD-47D4-953F-FC970261B9FB}.Debug|x86.ActiveCfg = Debug|Any CPU | ||
| {AC3F0F1B-31CD-47D4-953F-FC970261B9FB}.Debug|x86.Build.0 = Debug|Any CPU | ||
| {AC3F0F1B-31CD-47D4-953F-FC970261B9FB}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
| {AC3F0F1B-31CD-47D4-953F-FC970261B9FB}.Release|Any CPU.Build.0 = Release|Any CPU | ||
| {AC3F0F1B-31CD-47D4-953F-FC970261B9FB}.Release|x64.ActiveCfg = Release|Any CPU | ||
| {AC3F0F1B-31CD-47D4-953F-FC970261B9FB}.Release|x64.Build.0 = Release|Any CPU | ||
| {AC3F0F1B-31CD-47D4-953F-FC970261B9FB}.Release|x86.ActiveCfg = Release|Any CPU | ||
| {AC3F0F1B-31CD-47D4-953F-FC970261B9FB}.Release|x86.Build.0 = Release|Any CPU | ||
| {73439EED-AE10-430D-99E5-2BD7E922BA8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
| {73439EED-AE10-430D-99E5-2BD7E922BA8E}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
| {73439EED-AE10-430D-99E5-2BD7E922BA8E}.Debug|x64.ActiveCfg = Debug|Any CPU | ||
| {73439EED-AE10-430D-99E5-2BD7E922BA8E}.Debug|x64.Build.0 = Debug|Any CPU | ||
| {73439EED-AE10-430D-99E5-2BD7E922BA8E}.Debug|x86.ActiveCfg = Debug|Any CPU | ||
| {73439EED-AE10-430D-99E5-2BD7E922BA8E}.Debug|x86.Build.0 = Debug|Any CPU | ||
| {73439EED-AE10-430D-99E5-2BD7E922BA8E}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
| {73439EED-AE10-430D-99E5-2BD7E922BA8E}.Release|Any CPU.Build.0 = Release|Any CPU | ||
| {73439EED-AE10-430D-99E5-2BD7E922BA8E}.Release|x64.ActiveCfg = Release|Any CPU | ||
| {73439EED-AE10-430D-99E5-2BD7E922BA8E}.Release|x64.Build.0 = Release|Any CPU | ||
| {73439EED-AE10-430D-99E5-2BD7E922BA8E}.Release|x86.ActiveCfg = Release|Any CPU | ||
| {73439EED-AE10-430D-99E5-2BD7E922BA8E}.Release|x86.Build.0 = Release|Any CPU | ||
| {A664D19C-0BDC-4B5F-AD31-C7BA0217DD22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
| {A664D19C-0BDC-4B5F-AD31-C7BA0217DD22}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
| {A664D19C-0BDC-4B5F-AD31-C7BA0217DD22}.Debug|x64.ActiveCfg = Debug|Any CPU | ||
| {A664D19C-0BDC-4B5F-AD31-C7BA0217DD22}.Debug|x64.Build.0 = Debug|Any CPU | ||
| {A664D19C-0BDC-4B5F-AD31-C7BA0217DD22}.Debug|x86.ActiveCfg = Debug|Any CPU | ||
| {A664D19C-0BDC-4B5F-AD31-C7BA0217DD22}.Debug|x86.Build.0 = Debug|Any CPU | ||
| {A664D19C-0BDC-4B5F-AD31-C7BA0217DD22}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
| {A664D19C-0BDC-4B5F-AD31-C7BA0217DD22}.Release|Any CPU.Build.0 = Release|Any CPU | ||
| {A664D19C-0BDC-4B5F-AD31-C7BA0217DD22}.Release|x64.ActiveCfg = Release|Any CPU | ||
| {A664D19C-0BDC-4B5F-AD31-C7BA0217DD22}.Release|x64.Build.0 = Release|Any CPU | ||
| {A664D19C-0BDC-4B5F-AD31-C7BA0217DD22}.Release|x86.ActiveCfg = Release|Any CPU | ||
| {A664D19C-0BDC-4B5F-AD31-C7BA0217DD22}.Release|x86.Build.0 = Release|Any CPU | ||
| EndGlobalSection | ||
| GlobalSection(SolutionProperties) = preSolution | ||
| HideSolutionNode = FALSE | ||
| EndGlobalSection | ||
| GlobalSection(NestedProjects) = preSolution | ||
| {73439EED-AE10-430D-99E5-2BD7E922BA8E} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} | ||
| {A664D19C-0BDC-4B5F-AD31-C7BA0217DD22} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} | ||
| EndGlobalSection | ||
| EndGlobal |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| namespace Domain.Entities; | ||
|
|
||
| public abstract class BaseEntity<TKey> | ||
| { | ||
| public TKey Id { get; set; } = default!; | ||
| public DateTime CreatedAt { get; set; } = DateTime.UtcNow; | ||
| public DateTime UpdatedAt { get; set; } = DateTime.UtcNow; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| namespace Domain.Entities; | ||
|
|
||
| public class SampleEntity : BaseEntity<Guid> | ||
| { | ||
| public string Name { get; set; } = default!; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| using System.Linq.Expressions; | ||
|
|
||
| namespace Domain.Interfaces; | ||
|
|
||
| public interface IRepository<TEntity> : IAsyncDisposable where TEntity : class | ||
| { | ||
| IQueryable<TEntity> Query(bool asNoTracking = true); | ||
|
|
||
| Task<TEntity?> GetByIdAsync<TKey>(TKey id, CancellationToken cancellationToken = default); | ||
|
|
||
| Task<List<TEntity>> ListAsync(Expression<Func<TEntity, bool>>? predicate = null, CancellationToken cancellationToken = default); | ||
|
|
||
| Task<TEntity> AddAsync(TEntity entity, CancellationToken cancellationToken = default); | ||
|
|
||
| Task UpdateAsync(TEntity entity, CancellationToken cancellationToken = default); | ||
|
|
||
| Task DeleteAsync(TEntity entity, CancellationToken cancellationToken = default); | ||
|
|
||
| Task<int> DeleteAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default); | ||
|
|
||
| Task<int> UpdateAsync(Expression<Func<TEntity, bool>> predicate, object updateDefinition, CancellationToken cancellationToken = default); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| namespace Domain.Interfaces; | ||
|
|
||
| public interface IUnitOfWork : IAsyncDisposable | ||
| { | ||
| Task<int> SaveChangesAsync(CancellationToken cancellationToken = default); | ||
|
|
||
| // TODO: implement transaction management | ||
| // Task<object> BeginTransactionAsync(CancellationToken cancellationToken = default); | ||
| } |
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| using Domain.Entities; | ||
| using Microsoft.EntityFrameworkCore; | ||
|
|
||
| namespace Infra.Data; | ||
| public class DataContext : DbContext | ||
| { | ||
| public DataContext(DbContextOptions<DataContext> opts) : base(opts) { } | ||
|
|
||
| public virtual DbSet<SampleEntity> Products => Set<SampleEntity>(); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| using Infra.Data; | ||
| using Domain.Interfaces; | ||
| using Microsoft.EntityFrameworkCore; | ||
| using System.Linq.Expressions; | ||
| using Microsoft.EntityFrameworkCore.Query; | ||
|
|
||
| namespace Infra.Repositories; | ||
|
|
||
| public class Repository<TEntity> : IRepository<TEntity> where TEntity : class | ||
| { | ||
| private readonly DataContext _dataContext; | ||
| private readonly DbSet<TEntity> _dbSet; | ||
| private int _disposed; | ||
|
|
||
| public Repository(DataContext dataContext) | ||
| { | ||
| _dataContext = dataContext; | ||
| _dbSet = dataContext.Set<TEntity>(); | ||
| } | ||
|
|
||
| public IQueryable<TEntity> Query(bool asNoTracking = true) => (asNoTracking ? _dbSet.AsNoTracking() : _dbSet).AsQueryable(); | ||
|
|
||
| public Task<TEntity?> GetByIdAsync<TKey>(TKey id, CancellationToken cancellationToken = default) | ||
| { | ||
| return _dbSet.FindAsync(new object?[] { id }!, cancellationToken).AsTask(); | ||
| } | ||
|
|
||
| public Task<List<TEntity>> ListAsync(Expression<Func<TEntity, bool>>? predicate = null, CancellationToken cancellationToken = default) | ||
| { | ||
| IQueryable<TEntity> query = _dbSet; | ||
| if (predicate is not null) query = query.Where(predicate); | ||
| return query.ToListAsync(cancellationToken); | ||
| } | ||
|
|
||
| public async Task<TEntity> AddAsync(TEntity entity, CancellationToken cancellationToken = default) | ||
| { | ||
| await _dbSet.AddAsync(entity, cancellationToken); | ||
|
|
||
| return entity; | ||
| } | ||
|
|
||
| public Task UpdateAsync(TEntity entity, CancellationToken cancellationToken = default) | ||
| { | ||
| _dbSet.Update(entity); | ||
|
|
||
| return Task.CompletedTask; | ||
| } | ||
|
|
||
| public Task DeleteAsync(TEntity entity, CancellationToken cancellationToken = default) | ||
| { | ||
| _dbSet.Remove(entity); | ||
|
|
||
| return Task.CompletedTask; | ||
| } | ||
|
|
||
| public Task<int> DeleteAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default) | ||
| { | ||
| return _dbSet.Where(predicate).ExecuteDeleteAsync(cancellationToken); | ||
| } | ||
|
|
||
| public Task<int> UpdateAsync(Expression<Func<TEntity, bool>> predicate, object updateDefinition, CancellationToken cancellationToken = default) | ||
| { | ||
| if (updateDefinition is not Expression<Func<SetPropertyCalls<TEntity>, SetPropertyCalls<TEntity>>> expression) | ||
| { | ||
| throw new InvalidOperationException($"Invalid update definition for type '{typeof(TEntity).Name}'. Expected an expression of type Expression<Func<SetPropertyCalls<{typeof(TEntity).Name}>, SetPropertyCalls<{typeof(TEntity).Name}>>>."); | ||
| } | ||
|
|
||
| return _dbSet.Where(predicate).ExecuteUpdateAsync(expression, cancellationToken); | ||
| } | ||
|
|
||
| public async ValueTask DisposeAsync() | ||
| { | ||
| if (Interlocked.Exchange(ref _disposed, 1) == 0) | ||
| { | ||
| await _dataContext.DisposeAsync(); | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| using Infra.Data; | ||
| using Domain.Interfaces; | ||
|
|
||
| namespace Infra.Repositories; | ||
|
|
||
| public class UnitOfWork : IUnitOfWork | ||
| { | ||
| private readonly DataContext _dataContext; | ||
| private int _disposed; | ||
|
|
||
| public UnitOfWork(DataContext dataContext) => _dataContext = dataContext; | ||
|
|
||
| public Task<int> SaveChangesAsync(CancellationToken cancellationToken = default) => _dataContext.SaveChangesAsync(cancellationToken); | ||
|
|
||
| public async ValueTask DisposeAsync() | ||
| { | ||
| if (Interlocked.Exchange(ref _disposed, 1) == 0) | ||
| { | ||
| await _dataContext.DisposeAsync(); | ||
| } | ||
| } | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.