Skip to content

Commit dbcdc53

Browse files
Merge pull request #12 from workcontrolgit/develop
Enhance with complete sample table set and code for EF Core
2 parents 0cc3d04 + 3763494 commit dbcdc53

File tree

87 files changed

+1160
-684
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

87 files changed

+1160
-684
lines changed

Apiresources.Application/Apiresources.Application.csproj

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66
</PropertyGroup>
77

88
<ItemGroup>
9-
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.0" />
10-
<PackageReference Include="FluentValidation" Version="11.5.1" />
11-
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.5.1" />
12-
<PackageReference Include="MediatR" Version="12.2.0" />
13-
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="11.1.0" />
9+
<PackageReference Include="AutoMapper" Version="13.0.1" />
10+
<PackageReference Include="FluentValidation" Version="11.9.2" />
11+
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.9.2" />
12+
<PackageReference Include="LinqKit.Microsoft.EntityFrameworkCore" Version="8.1.5" />
13+
<PackageReference Include="MediatR" Version="12.4.0" />
14+
<PackageReference Include="Scrutor" Version="4.2.2" />
1415
</ItemGroup>
1516

1617
<ItemGroup>

Apiresources.Application/Behaviours/ValidationBehaviour.cs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,4 @@
1-
using FluentValidation;
2-
using MediatR;
3-
using System.Collections.Generic;
4-
using System.Linq;
5-
using System.Threading;
6-
using System.Threading.Tasks;
7-
8-
namespace $safeprojectname$.Behaviours
1+
namespace $safeprojectname$.Behaviours
92
{
103
public class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
114
where TRequest : IRequest<TResponse>
@@ -21,11 +14,13 @@ public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TRe
2114
{
2215
if (_validators.Any())
2316
{
24-
var context = new FluentValidation.ValidationContext<TRequest>(request);
25-
var validationResults = await Task.WhenAll(_validators.Select(v => v.ValidateAsync(context, cancellationToken)));
26-
var failures = validationResults.SelectMany(r => r.Errors).Where(f => f != null).ToList();
17+
var context = new ValidationContext<TRequest>(request);
18+
var validationResults = await Task.WhenAll(_validators.Select(validator => validator.ValidateAsync(context, cancellationToken)));
19+
var failures = validationResults.SelectMany(validationResult => validationResult.Errors)
20+
.Where(validationResult => validationResult != null)
21+
.ToList();
2722

28-
if (failures.Count != 0)
23+
if (failures.Any())
2924
throw new Exceptions.ValidationException(failures);
3025
}
3126
return await next();

Apiresources.Application/Exceptions/ApiException.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using System;
2-
using System.Globalization;
1+

32

43
namespace $safeprojectname$.Exceptions
54
{

Apiresources.Application/Exceptions/ValidationException.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
using FluentValidation.Results;
2-
using System;
3-
using System.Collections.Generic;
4-
5-
namespace $safeprojectname$.Exceptions
1+
namespace $safeprojectname$.Exceptions
62
{
73
public class ValidationException : Exception
84
{
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
namespace $safeprojectname$.Features.Departments.Queries.GetDepartments
2+
{
3+
/// <summary>
4+
/// GetAllDepartmentsQuery - handles media IRequest
5+
/// BaseRequestParameter - contains paging parameters
6+
/// To add filter/search parameters, add search properties to the body of this class
7+
/// </summary>
8+
public class GetDepartmentsQuery : ListParameter, IRequest<IEnumerable<GetDepartmentsViewModel>>
9+
{
10+
}
11+
12+
public class GetAllDepartmentsQueryHandler : IRequestHandler<GetDepartmentsQuery, IEnumerable<GetDepartmentsViewModel>>
13+
{
14+
private readonly IDepartmentRepositoryAsync _repository;
15+
private readonly IModelHelper _modelHelper;
16+
private readonly IMapper _mapper;
17+
18+
/// <summary>
19+
/// Constructor for GetAllDepartmentsQueryHandler class.
20+
/// </summary>
21+
/// <param name="repository">IDepartmentRepositoryAsync object.</param>
22+
/// <param name="modelHelper">IModelHelper object.</param>
23+
/// <returns>
24+
/// GetAllDepartmentsQueryHandler object.
25+
/// </returns>
26+
public GetAllDepartmentsQueryHandler(IDepartmentRepositoryAsync repository, IModelHelper modelHelper, IMapper mapper)
27+
{
28+
_repository = repository;
29+
_modelHelper = modelHelper;
30+
_mapper = mapper;
31+
}
32+
33+
/// <summary>
34+
/// Handles the GetDepartmentsQuery request and returns a PagedResponse containing the requested data.
35+
/// </summary>
36+
/// <param name="request">The GetDepartmentsQuery request.</param>
37+
/// <param name="cancellationToken">The cancellation token.</param>
38+
/// <returns>A PagedResponse containing the requested data.</returns>
39+
public async Task<IEnumerable<GetDepartmentsViewModel>> Handle(GetDepartmentsQuery request, CancellationToken cancellationToken)
40+
{
41+
string fields = _modelHelper.GetModelFields<GetDepartmentsViewModel>();
42+
string defaultOrderByColumn = "Name";
43+
44+
string orderBy = string.Empty;
45+
46+
// if the request orderby is not null
47+
if (!string.IsNullOrEmpty(request.OrderBy))
48+
{
49+
// check to make sure order by field is valid and in the view model
50+
orderBy = _modelHelper.ValidateModelFields<GetDepartmentsViewModel>(request.OrderBy);
51+
}
52+
53+
// if the order by is invalid
54+
if (string.IsNullOrEmpty(orderBy))
55+
{
56+
//default fields from view model
57+
orderBy = defaultOrderByColumn;
58+
}
59+
60+
var data = await _repository.GetAllShapeAsync(orderBy, fields);
61+
62+
// automap to ViewModel
63+
var viewModel = _mapper.Map<IEnumerable<GetDepartmentsViewModel>>(data);
64+
65+
return viewModel;
66+
}
67+
}
68+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+

2+
3+
namespace $safeprojectname$.Features.Departments.Queries.GetDepartments
4+
{
5+
public class GetDepartmentsViewModel //: Department
6+
{
7+
public Guid Id { get; set; }
8+
public string Name { get; set; }
9+
}
10+
}
Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,4 @@
1-
using $safeprojectname$.Interfaces;
2-
using $safeprojectname$.Interfaces.Repositories;
3-
using $safeprojectname$.Parameters;
4-
using $safeprojectname$.Wrappers;
5-
using $ext_projectname$.Domain.Entities;
6-
using AutoMapper;
7-
using MediatR;
8-
using System.Collections.Generic;
9-
using System.Threading;
10-
using System.Threading.Tasks;
11-
12-
namespace $safeprojectname$.Features.Employees.Queries.GetEmployees
1+
namespace $safeprojectname$.Features.Employees.Queries.GetEmployees
132
{
143
/// <summary>
154
/// GetAllEmployeesQuery - handles media IRequest
@@ -19,21 +8,21 @@ namespace $safeprojectname$.Features.Employees.Queries.GetEmployees
198
public class GetEmployeesQuery : QueryParameter, IRequest<PagedResponse<IEnumerable<Entity>>>
209
{
2110
//examples:
22-
public string EmployeeNumber { get; set; }
23-
public string EmployeeTitle { get; set; }
2411
public string LastName { get; set; }
12+
2513
public string FirstName { get; set; }
2614
public string Email { get; set; }
15+
public string EmployeeNumber { get; set; }
16+
public string PositionTitle { get; set; }
2717

18+
public ListParameter ShapeParameter { get; set; }
2819
}
2920

3021
public class GetAllEmployeesQueryHandler : IRequestHandler<GetEmployeesQuery, PagedResponse<IEnumerable<Entity>>>
3122
{
3223
private readonly IEmployeeRepositoryAsync _employeeRepository;
3324
private readonly IModelHelper _modelHelper;
3425

35-
36-
3726
/// <summary>
3827
/// Constructor for GetAllEmployeesQueryHandler class.
3928
/// </summary>
@@ -48,8 +37,6 @@ public GetAllEmployeesQueryHandler(IEmployeeRepositoryAsync employeeRepository,
4837
_modelHelper = modelHelper;
4938
}
5039

51-
52-
5340
/// <summary>
5441
/// Handles the GetEmployeesQuery request and returns a PagedResponse containing the requested data.
5542
/// </summary>
@@ -58,25 +45,25 @@ public GetAllEmployeesQueryHandler(IEmployeeRepositoryAsync employeeRepository,
5845
/// <returns>A PagedResponse containing the requested data.</returns>
5946
public async Task<PagedResponse<IEnumerable<Entity>>> Handle(GetEmployeesQuery request, CancellationToken cancellationToken)
6047
{
61-
var validFilter = request;
48+
var objRequest = request;
6249
//filtered fields security
63-
if (!string.IsNullOrEmpty(validFilter.Fields))
50+
if (!string.IsNullOrEmpty(objRequest.Fields))
6451
{
6552
//limit to fields in view model
66-
validFilter.Fields = _modelHelper.ValidateModelFields<GetEmployeesViewModel>(validFilter.Fields);
53+
objRequest.Fields = _modelHelper.ValidateModelFields<GetEmployeesViewModel>(objRequest.Fields);
6754
}
68-
if (string.IsNullOrEmpty(validFilter.Fields))
55+
else
6956
{
7057
//default fields from view model
71-
validFilter.Fields = _modelHelper.GetModelFields<GetEmployeesViewModel>();
58+
objRequest.Fields = _modelHelper.GetModelFields<GetEmployeesViewModel>();
7259
}
7360
// query based on filter
74-
var qryResult = await _employeeRepository.GetPagedEmployeeResponseAsync(validFilter);
61+
var qryResult = await _employeeRepository.GetEmployeeResponseAsync(objRequest);
7562
var data = qryResult.data;
7663
RecordsCount recordCount = qryResult.recordsCount;
7764

7865
// response wrapper
79-
return new PagedResponse<IEnumerable<Entity>>(data, validFilter.PageNumber, validFilter.PageSize, recordCount);
66+
return new PagedResponse<IEnumerable<Entity>>(data, objRequest.PageNumber, objRequest.PageSize, recordCount);
8067
}
8168
}
8269
}
Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using $ext_projectname$.Domain.Enums;
2-
using System;
1+

32

43
namespace $safeprojectname$.Features.Employees.Queries.GetEmployees
54
{
@@ -9,12 +8,14 @@ public class GetEmployeesViewModel
98
public string FirstName { get; set; }
109
public string MiddleName { get; set; }
1110
public string LastName { get; set; }
12-
public string EmployeeTitle { get; set; }
13-
public DateTime DOB { get; set; }
11+
public DateTime Birthday { get; set; }
1412
public string Email { get; set; }
1513
public Gender Gender { get; set; }
1614
public string EmployeeNumber { get; set; }
17-
public string Suffix { get; set; }
15+
public string Prefix { get; set; }
1816
public string Phone { get; set; }
17+
public virtual Position Position { get; set; }
18+
public decimal Salary { get; set; }
19+
1920
}
2021
}

Apiresources.Application/Features/Employees/Queries/GetEmployees/PagedEmployeesQuery.cs

Lines changed: 20 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,13 @@
1-
using AutoMapper;
2-
using MediatR;
3-
using System.Collections.Generic;
4-
using System.Threading;
5-
using System.Threading.Tasks;
6-
using $safeprojectname$.Interfaces;
7-
using $safeprojectname$.Interfaces.Repositories;
8-
using $safeprojectname$.Parameters;
9-
using $safeprojectname$.Wrappers;
10-
using $ext_projectname$.Domain.Entities;
11-
12-
namespace $safeprojectname$.Features.Employees.Queries.GetEmployees
1+
namespace $safeprojectname$.Features.Employees.Queries.GetEmployees
132
{
14-
public partial class PagedEmployeesQuery : IRequest<PagedDataTableResponse<IEnumerable<Entity>>>
3+
public partial class PagedEmployeesQuery : QueryParameter, IRequest<PagedDataTableResponse<IEnumerable<Entity>>>
154
{
165
//strong type input parameters
176
public int Draw { get; set; } //page number
7+
188
public int Start { get; set; } //Paging first record indicator. This is the start point in the current data set (0 index based - i.e. 0 is the first record).
199
public int Length { get; set; } //page size
20-
public IList<SortOrder> SortOrder { get; set; } //Order by
10+
public IList<SortOrder> Order { get; set; } //Order by
2111
public Search Search { get; set; } //search criteria
2212
public IList<Column> Columns { get; set; } //select fields
2313
}
@@ -27,8 +17,6 @@ public class PageEmployeeQueryHandler : IRequestHandler<PagedEmployeesQuery, Pag
2717
private readonly IEmployeeRepositoryAsync _repository;
2818
private readonly IModelHelper _modelHelper;
2919

30-
31-
3220
/// <summary>
3321
/// Constructor for PageEmployeeQueryHandler class.
3422
/// </summary>
@@ -43,8 +31,6 @@ public PageEmployeeQueryHandler(IEmployeeRepositoryAsync repository, IModelHelpe
4331
_modelHelper = modelHelper;
4432
}
4533

46-
47-
4834
/// <summary>
4935
/// Handles the PagedEmployeesQuery request and returns a PagedDataTableResponse.
5036
/// </summary>
@@ -53,50 +39,45 @@ public PageEmployeeQueryHandler(IEmployeeRepositoryAsync repository, IModelHelpe
5339
/// <returns>A PagedDataTableResponse.</returns>
5440
public async Task<PagedDataTableResponse<IEnumerable<Entity>>> Handle(PagedEmployeesQuery request, CancellationToken cancellationToken)
5541
{
56-
var validFilter = new GetEmployeesQuery();
42+
var objRequest = request;
5743

5844
// Draw map to PageNumber
59-
validFilter.PageNumber = (request.Start / request.Length) + 1;
45+
objRequest.PageNumber = (request.Start / request.Length) + 1;
6046
// Length map to PageSize
61-
validFilter.PageSize = request.Length;
47+
objRequest.PageSize = request.Length;
6248

6349
// Map order > OrderBy
64-
var colOrder = request.SortOrder[0];
50+
var colOrder = request.Order[0];
6551
switch (colOrder.Column)
6652
{
6753
case 0:
68-
validFilter.OrderBy = colOrder.Dir == "asc" ? "LastName" : "LastName DESC";
54+
objRequest.OrderBy = colOrder.Dir == "asc" ? "LastName" : "LastName DESC";
6955
break;
7056

7157
case 1:
72-
validFilter.OrderBy = colOrder.Dir == "asc" ? "FirstName" : "FirstName DESC";
58+
objRequest.OrderBy = colOrder.Dir == "asc" ? "FirstName" : "FirstName DESC";
7359
break;
7460

7561
case 2:
76-
validFilter.OrderBy = colOrder.Dir == "asc" ? "EmployeeTitle" : "EmployeeTitle DESC";
62+
objRequest.OrderBy = colOrder.Dir == "asc" ? "Email" : "Email DESC";
7763
break;
64+
7865
case 3:
79-
validFilter.OrderBy = colOrder.Dir == "asc" ? "Email" : "Email DESC";
66+
objRequest.OrderBy = colOrder.Dir == "asc" ? "EmployeeNumber" : "EmployeeNumber DESC";
8067
break;
81-
}
8268

83-
// Map Search > searchable columns
84-
if (!string.IsNullOrEmpty(request.Search.Value))
85-
{
86-
//limit to fields in view model
87-
validFilter.LastName = request.Search.Value;
88-
validFilter.FirstName = request.Search.Value;
89-
validFilter.Email = request.Search.Value;
90-
validFilter.EmployeeNumber = request.Search.Value;
91-
validFilter.EmployeeTitle = request.Search.Value;
69+
case 4:
70+
objRequest.OrderBy = colOrder.Dir == "asc" ? "Position.PositionTitle" : "Position.PositionTitle DESC";
71+
break;
9272
}
93-
if (string.IsNullOrEmpty(validFilter.Fields))
73+
74+
if (string.IsNullOrEmpty(objRequest.Fields))
9475
{
9576
//default fields from view model
96-
validFilter.Fields = _modelHelper.GetModelFields<GetEmployeesViewModel>();
77+
objRequest.Fields = _modelHelper.GetModelFields<GetEmployeesViewModel>();
9778
}
9879
// query based on filter
99-
var qryResult = await _repository.GetPagedEmployeeResponseAsync(validFilter);
80+
var qryResult = await _repository.GetPagedEmployeeResponseAsync(objRequest);
10081
var data = qryResult.data;
10182
RecordsCount recordCount = qryResult.recordsCount;
10283

Apiresources.Application/Features/Positions/Commands/CreatePosition/CreatePositionCommand.cs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,13 @@
1-
using AutoMapper;
2-
using MediatR;
3-
using $safeprojectname$.Interfaces.Repositories;
4-
using $safeprojectname$.Wrappers;
5-
using $ext_projectname$.Domain.Entities;
6-
using System;
7-
using System.Threading;
8-
using System.Threading.Tasks;
9-
10-
namespace $safeprojectname$.Features.Positions.Commands.CreatePosition
1+
namespace $safeprojectname$.Features.Positions.Commands.CreatePosition
112
{
123
public partial class CreatePositionCommand : IRequest<Response<Guid>>
134
{
145
public string PositionTitle { get; set; }
156
public string PositionNumber { get; set; }
167
public string PositionDescription { get; set; }
17-
public decimal PositionSalary { get; set; }
8+
public Guid DepartmentId { get; set; }
9+
public Guid SalaryRangeId { get; set; }
10+
1811
}
1912

2013
public class CreatePositionCommandHandler : IRequestHandler<CreatePositionCommand, Response<Guid>>

0 commit comments

Comments
 (0)