Skip to content

Commit b19f581

Browse files
committed
refactored repository abstractions and implementations
1 parent 18d5679 commit b19f581

File tree

7 files changed

+170
-217
lines changed

7 files changed

+170
-217
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,9 @@
1-
using System.Linq.Expressions;
2-
using Logistics.Domain.Core;
3-
using Logistics.Domain.Specifications;
1+
using Logistics.Domain.Core;
42

53
namespace Logistics.Domain.Persistence;
64

75
/// <summary>
8-
/// Generic repository.
6+
/// Master repository.
97
/// </summary>
108
/// <typeparam name="TEntity">Class that implements the <see cref="IEntity{TKey}"/> interface</typeparam>
11-
public interface IMasterRepository<TEntity> where TEntity : class, IEntity<string>
12-
{
13-
IQueryable<TEntity> ApplySpecification(ISpecification<TEntity> specification);
14-
15-
IQueryable<TEntity> Query();
16-
17-
/// <summary>
18-
/// Asynchronously counts number of entities.
19-
/// </summary>
20-
/// <param name="predicate">Predicate to filter query</param>
21-
/// <returns>Number of elements that satisfies the specified condition</returns>
22-
Task<int> CountAsync(Expression<Func<TEntity, bool>>? predicate = default);
23-
24-
/// <summary>
25-
/// Gets an entity object by ID.
26-
/// </summary>
27-
/// <param name="id">Entity primary key</param>
28-
/// <returns>Entity object</returns>
29-
Task<TEntity?> GetByIdAsync(string id);
30-
31-
/// <summary>
32-
/// Gets an entity object filtered by predicate.
33-
/// </summary>
34-
/// <param name="predicate">Predicate to filter query</param>
35-
/// <returns>Entity object</returns>
36-
Task<TEntity?> GetAsync(Expression<Func<TEntity, bool>> predicate);
37-
38-
/// <summary>
39-
/// Gets a list of the entity objects
40-
/// </summary>
41-
/// <param name="predicate">Predicate to filter query</param>
42-
/// <returns>List of entity objects</returns>
43-
Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> predicate);
44-
45-
/// <summary>
46-
/// Gets a list of the entity objects
47-
/// </summary>
48-
/// <param name="specification">Specification</param>
49-
/// <returns>List of entity objects</returns>
50-
Task<List<TEntity>> GetListAsync(ISpecification<TEntity>? specification = default);
51-
52-
/// <summary>
53-
/// Adds new entry to database.
54-
/// </summary>
55-
/// <param name="entity">Entity object</param>
56-
Task AddAsync(TEntity entity);
57-
58-
/// <summary>
59-
/// Updates existing entry.
60-
/// </summary>
61-
/// <param name="entity">Entity object</param>
62-
void Update(TEntity entity);
63-
64-
/// <summary>
65-
/// Deletes entity object from database.
66-
/// </summary>
67-
/// <param name="entity">Entity object</param>
68-
void Delete(TEntity? entity);
69-
}
9+
public interface IMasterRepository<TEntity> : IRepository<TEntity, string> where TEntity : class, IEntity<string>;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
using System.Linq.Expressions;
2+
using Logistics.Domain.Core;
3+
using Logistics.Domain.Specifications;
4+
5+
namespace Logistics.Domain.Persistence;
6+
7+
/// <summary>
8+
/// Generic repository.
9+
/// </summary>
10+
/// <typeparam name="TEntity">Class that implements the <see cref="IEntity{TKey}"/> interface</typeparam>
11+
/// <typeparam name="TEntityKey">The data type of entity primary key</typeparam>
12+
public interface IRepository<TEntity, in TEntityKey> where TEntity : class, IEntity<TEntityKey>
13+
{
14+
IQueryable<TEntity> ApplySpecification(ISpecification<TEntity> specification);
15+
16+
IQueryable<TEntity> Query();
17+
18+
/// <summary>
19+
/// Asynchronously counts number of entities.
20+
/// </summary>
21+
/// <param name="predicate">Predicate to filter query</param>
22+
/// <returns>Number of elements that satisfies the specified condition</returns>
23+
Task<int> CountAsync(Expression<Func<TEntity, bool>>? predicate = default);
24+
25+
/// <summary>
26+
/// Gets an entity object by ID.
27+
/// </summary>
28+
/// <param name="id">Entity primary key</param>
29+
/// <returns>Entity object</returns>
30+
Task<TEntity?> GetByIdAsync(TEntityKey id);
31+
32+
/// <summary>
33+
/// Gets an entity object filtered by predicate.
34+
/// </summary>
35+
/// <param name="predicate">Predicate to filter query</param>
36+
/// <returns>Entity object</returns>
37+
Task<TEntity?> GetAsync(Expression<Func<TEntity, bool>> predicate);
38+
39+
/// <summary>
40+
/// Gets a list of the entity objects
41+
/// </summary>
42+
/// <param name="predicate">Predicate to filter query</param>
43+
/// <returns>List of entity objects</returns>
44+
Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> predicate);
45+
46+
/// <summary>
47+
/// Gets a list of the entity objects
48+
/// </summary>
49+
/// <param name="specification">Specification</param>
50+
/// <returns>List of entity objects</returns>
51+
Task<List<TEntity>> GetListAsync(ISpecification<TEntity>? specification = default);
52+
53+
/// <summary>
54+
/// Adds new entry to database.
55+
/// </summary>
56+
/// <param name="entity">Entity object</param>
57+
Task AddAsync(TEntity entity);
58+
59+
/// <summary>
60+
/// Updates existing entry.
61+
/// </summary>
62+
/// <param name="entity">Entity object</param>
63+
void Update(TEntity entity);
64+
65+
/// <summary>
66+
/// Deletes entity object from database.
67+
/// </summary>
68+
/// <param name="entity">Entity object</param>
69+
void Delete(TEntity? entity);
70+
}
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
using Logistics.Domain.Core;
2-
using Logistics.Domain.Entities;
32

43
namespace Logistics.Domain.Persistence;
54

65
/// <summary>
76
/// Tenant's repository.
87
/// </summary>
9-
public interface ITenantRepository<TEntity> : IMasterRepository<TEntity> where TEntity : class, ITenantEntity
10-
{
11-
}
8+
public interface ITenantRepository<TEntity> : IRepository<TEntity, string> where TEntity : class, ITenantEntity;
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,13 @@
1-
using System.Linq.Expressions;
2-
using Logistics.Domain.Core;
1+
using Logistics.Domain.Core;
32
using Logistics.Domain.Persistence;
4-
using Logistics.Domain.Specifications;
53
using Logistics.Infrastructure.EF.Data;
6-
using Microsoft.EntityFrameworkCore;
74

85
namespace Logistics.Infrastructure.EF.Persistence;
96

10-
public class MasterRepository<TEntity> : IMasterRepository<TEntity>
7+
public class MasterRepository<TEntity> : Repository<MasterDbContext, TEntity, string>, IMasterRepository<TEntity>
118
where TEntity : class, IEntity<string>
129
{
13-
private readonly MasterDbContext _masterDbContext;
14-
15-
public MasterRepository(MasterDbContext masterDbContext)
10+
public MasterRepository(MasterDbContext masterDbContext) : base(masterDbContext)
1611
{
17-
_masterDbContext = masterDbContext;
18-
}
19-
20-
public IQueryable<TEntity> ApplySpecification(ISpecification<TEntity> specification)
21-
{
22-
return SpecificationEvaluator<TEntity>.GetQuery(_masterDbContext.Set<TEntity>(), specification);
23-
}
24-
25-
public IQueryable<TEntity> Query()
26-
{
27-
return _masterDbContext.Set<TEntity>();
28-
}
29-
30-
public Task<int> CountAsync(Expression<Func<TEntity, bool>>? predicate = default)
31-
{
32-
if (predicate is null)
33-
{
34-
return _masterDbContext.Set<TEntity>().CountAsync();
35-
}
36-
37-
return _masterDbContext.Set<TEntity>().CountAsync(predicate);
38-
}
39-
40-
public Task<TEntity?> GetByIdAsync(string id)
41-
{
42-
return _masterDbContext.Set<TEntity>().FindAsync(id).AsTask();
43-
}
44-
45-
public Task<TEntity?> GetAsync(Expression<Func<TEntity, bool>> predicate)
46-
{
47-
return _masterDbContext.Set<TEntity>().FirstOrDefaultAsync(predicate);
48-
}
49-
50-
public Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> predicate)
51-
{
52-
return _masterDbContext.Set<TEntity>().Where(predicate).ToListAsync();
53-
}
54-
55-
public Task<List<TEntity>> GetListAsync(ISpecification<TEntity>? specification = default)
56-
{
57-
if (specification is null)
58-
{
59-
return _masterDbContext.Set<TEntity>().ToListAsync();
60-
}
61-
62-
return SpecificationEvaluator<TEntity>.GetQuery(_masterDbContext.Set<TEntity>(), specification).ToListAsync();
63-
}
64-
65-
public Task AddAsync(TEntity entity)
66-
{
67-
return _masterDbContext.Set<TEntity>().AddAsync(entity).AsTask();
68-
}
69-
70-
public void Update(TEntity entity)
71-
{
72-
_masterDbContext.Set<TEntity>().Update(entity);
73-
}
74-
75-
public void Delete(TEntity? entity)
76-
{
77-
if (entity is null)
78-
{
79-
return;
80-
}
81-
82-
_masterDbContext.Set<TEntity>().Remove(entity);
8312
}
8413
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
using System.Linq.Expressions;
2+
using Logistics.Domain.Core;
3+
using Logistics.Domain.Persistence;
4+
using Logistics.Domain.Specifications;
5+
using Microsoft.EntityFrameworkCore;
6+
7+
namespace Logistics.Infrastructure.EF.Persistence;
8+
9+
public class Repository<TDbContext, TEntity, TEntityKey> : IRepository<TEntity, TEntityKey>
10+
where TEntity : class, IEntity<TEntityKey>
11+
where TDbContext : DbContext
12+
{
13+
private readonly TDbContext _dbContext;
14+
15+
protected Repository(TDbContext dbContext)
16+
{
17+
_dbContext = dbContext;
18+
}
19+
20+
public IQueryable<TEntity> ApplySpecification(ISpecification<TEntity> specification)
21+
{
22+
return SpecificationEvaluator<TEntity, TEntityKey>.GetQuery(_dbContext.Set<TEntity>(), specification);
23+
}
24+
25+
public IQueryable<TEntity> Query()
26+
{
27+
return _dbContext.Set<TEntity>();
28+
}
29+
30+
public Task<int> CountAsync(Expression<Func<TEntity, bool>>? predicate = default)
31+
{
32+
if (predicate is null)
33+
{
34+
return _dbContext.Set<TEntity>().CountAsync();
35+
}
36+
37+
return _dbContext.Set<TEntity>().CountAsync(predicate);
38+
}
39+
40+
public Task<TEntity?> GetByIdAsync(TEntityKey id)
41+
{
42+
return _dbContext.Set<TEntity>().FindAsync(id).AsTask();
43+
}
44+
45+
public Task<TEntity?> GetAsync(Expression<Func<TEntity, bool>> predicate)
46+
{
47+
return _dbContext.Set<TEntity>().FirstOrDefaultAsync(predicate);
48+
}
49+
50+
public Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> predicate)
51+
{
52+
return _dbContext.Set<TEntity>()
53+
.Where(predicate)
54+
.ToListAsync();
55+
}
56+
57+
public Task<List<TEntity>> GetListAsync(ISpecification<TEntity>? specification = default)
58+
{
59+
if (specification is null)
60+
{
61+
return _dbContext.Set<TEntity>().ToListAsync();
62+
}
63+
64+
return SpecificationEvaluator<TEntity, TEntityKey>
65+
.GetQuery(_dbContext.Set<TEntity>(), specification)
66+
.ToListAsync();
67+
}
68+
69+
public Task AddAsync(TEntity entity)
70+
{
71+
return _dbContext.Set<TEntity>().AddAsync(entity).AsTask();
72+
}
73+
74+
public void Update(TEntity entity)
75+
{
76+
_dbContext.Set<TEntity>().Update(entity);
77+
}
78+
79+
public void Delete(TEntity? entity)
80+
{
81+
if (entity is null)
82+
{
83+
return;
84+
}
85+
86+
_dbContext.Set<TEntity>().Remove(entity);
87+
}
88+
}

src/Core/Logistics.Infrastructure.EF/Persistence/SpecificationEvaluator.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
namespace Logistics.Infrastructure.EF.Persistence;
66

7-
public static class SpecificationEvaluator<TEntity> where TEntity : class, IEntity<string>
7+
public static class SpecificationEvaluator<TEntity, TEntityKey>
8+
where TEntity : class, IEntity<TEntityKey>
89
{
910
public static IQueryable<TEntity> GetQuery(IQueryable<TEntity> inputQuery, ISpecification<TEntity> specification)
1011
{

0 commit comments

Comments
 (0)