Skip to content

Commit df35489

Browse files
committed
chore: Update package versions and improve comments for clarity
1 parent a42b675 commit df35489

9 files changed

Lines changed: 113 additions & 170 deletions

File tree

Directory.Packages.props

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@
55
</PropertyGroup>
66
<ItemGroup>
77
<PackageVersion Include="BenchmarkDotNet" Version="0.15.8" />
8-
<PackageVersion Include="BridgingIT.DevKit.Application.JobScheduling" Version="10.0.2-preview.0.64" />
9-
<PackageVersion Include="BridgingIT.DevKit.Common.Mapping" Version="10.0.2-preview.0.64" />
10-
<PackageVersion Include="BridgingIT.DevKit.Common.Utilities.Xunit" Version="10.0.2-preview.0.64" />
11-
<PackageVersion Include="BridgingIT.DevKit.Domain" Version="10.0.2-preview.0.64" />
12-
<PackageVersion Include="BridgingIT.DevKit.Domain.CodeGen" Version="10.0.2-preview.0.64" />
13-
<PackageVersion Include="BridgingIT.DevKit.Infrastructure.EntityFramework" Version="10.0.2-preview.0.64" />
14-
<PackageVersion Include="BridgingIT.DevKit.Infrastructure.EntityFramework.SqlServer" Version="10.0.2-preview.0.64" />
15-
<PackageVersion Include="BridgingIT.DevKit.Presentation.Web" Version="10.0.2-preview.0.64" />
16-
<PackageVersion Include="BridgingIT.DevKit.Presentation.Web.JobScheduling" Version="10.0.2-preview.0.64" />
17-
<PackageVersion Include="BridgingIT.DevKit.Presentation.Serilog" Version="10.0.2-preview.0.64" />
8+
<PackageVersion Include="BridgingIT.DevKit.Application.JobScheduling" Version="10.0.2-preview.0.66" />
9+
<PackageVersion Include="BridgingIT.DevKit.Common.Mapping" Version="10.0.2-preview.0.66" />
10+
<PackageVersion Include="BridgingIT.DevKit.Common.Utilities.Xunit" Version="10.0.2-preview.0.66" />
11+
<PackageVersion Include="BridgingIT.DevKit.Domain" Version="10.0.2-preview.0.66" />
12+
<PackageVersion Include="BridgingIT.DevKit.Domain.CodeGen" Version="10.0.2-preview.0.66" />
13+
<PackageVersion Include="BridgingIT.DevKit.Infrastructure.EntityFramework" Version="10.0.2-preview.0.66" />
14+
<PackageVersion Include="BridgingIT.DevKit.Infrastructure.EntityFramework.SqlServer" Version="10.0.2-preview.0.66" />
15+
<PackageVersion Include="BridgingIT.DevKit.Presentation.Web" Version="10.0.2-preview.0.66" />
16+
<PackageVersion Include="BridgingIT.DevKit.Presentation.Web.JobScheduling" Version="10.0.2-preview.0.66" />
17+
<PackageVersion Include="BridgingIT.DevKit.Presentation.Serilog" Version="10.0.2-preview.0.66" />
1818
<PackageVersion Include="coverlet.collector" Version="6.0.4" />
1919
<PackageVersion Include="Dumpify" Version="0.6.6" />
2020
<PackageVersion Include="FluentAssertions.Web" Version="1.9.5" />

src/Modules/CoreModule/CoreModule.Application/Commands/CustomerCreateCommandHandler.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,18 @@ await Result<CustomerModel>
5858
.Log(logger, "Customer number created{@Number}", r => [r.Value.Number])
5959

6060
// STEP 4 — Create new Aggregate from request model
61-
.Bind(this.CreateEntity)
61+
.Bind(this.CreateAggregate)
6262

6363
// STEP 6 — Save new Aggregate to repository
6464
.BindResultAsync(this.PersistEntityAsync, this.CapturePersistedEntity, cancellationToken)
6565

6666
// STEP 7 — Side effects (audit/logging)
6767
.Log(logger, "AUDIT - Customer {Id} created for {Email}", r => [r.Value.Entity.Id, r.Value.Entity.Email.Value])
6868

69-
// STEP 8 — Map new Aggregate → Model
70-
.Map(this.ToModel)
71-
.Log(logger, "Entity mapped to {@Model}", r => [r.Value]);
69+
// STEP 8 — Map created Aggregate -> Model
70+
.Map(ctx => ctx.Entity)
71+
.MapResult<Customer, CustomerModel>(mapper) //.Map(this.ToModel)
72+
.Log(logger, "Aggregate mapped to {@Model}", r => [r.Value]);
7273

7374
private async Task<Result<long>> GenerateSequenceAsync(CustomerCreateContext ctx, CancellationToken ct)
7475
{
@@ -82,7 +83,7 @@ private CustomerCreateContext CaptureNumber(CustomerCreateContext ctx, long seq)
8283
return ctx;
8384
}
8485

85-
private Result<CustomerCreateContext> CreateEntity(CustomerCreateContext ctx)
86+
private Result<CustomerCreateContext> CreateAggregate(CustomerCreateContext ctx)
8687
{
8788
return Customer
8889
.Create(ctx.Model.FirstName, ctx.Model.LastName, ctx.Model.Email, ctx.Number)

src/Modules/CoreModule/CoreModule.Application/Commands/CustomerUpdateCommandHandler.cs

Lines changed: 54 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ namespace BridgingIT.DevKit.Examples.GettingStarted.Modules.CoreModule.Applicati
77

88
using BridgingIT.DevKit.Examples.GettingStarted.Modules.CoreModule.Domain.Events;
99
using BridgingIT.DevKit.Examples.GettingStarted.Modules.CoreModule.Domain.Model;
10+
using MediatR;
1011
using Microsoft.Extensions.Logging;
1112

1213
/// <summary>
1314
/// Handler for <see cref="CustomerUpdateCommand"/>.
14-
/// Maps DTO domain, checks business rules, updates the entity in the repository,
15+
/// Maps DTO -> domain, checks business rules, updates the entity in the repository,
1516
/// and maps back to <see cref="CustomerModel"/> for returning to the client.
1617
/// </summary>
1718
/// <remarks>
@@ -48,19 +49,11 @@ await repository.FindOneResultAsync(CustomerId.Create(request.Model.Id), cancell
4849
.Add(RuleSet.IsNotEmpty(e.FirstName)) // also validated in domain
4950
.Add(RuleSet.IsNotEmpty(e.LastName)) // also validated in domain
5051
.Add(RuleSet.NotEqual(e.LastName, "notallowed")) // also validated in domain
51-
//.Add(new EmailShouldBeUniqueRule(e.Email, repository)) // TODO: Check unique email excluding the current entity (currently disabled)
52+
//.Add(new EmailShouldBeUniqueRule(e.Email, repository)) // TODO: Check unique email excluding the current entity (currently disabled)
5253
.CheckAsync(cancellationToken), cancellationToken: cancellationToken)
5354

54-
// STEP 3 - Apply changes to Aggregate
55-
.Bind(e => e.ChangeName(request.Model.FirstName, request.Model.LastName))
56-
.Bind(e => e.ChangeEmail(request.Model.Email))
57-
.Bind(e => e.ChangeBirthDate(request.Model.DateOfBirth))
58-
.Bind(e => e.ChangeStatus(request.Model.Status))
59-
.Bind(e => this.UpdateAddresses(e, request.Model.Addresses))
60-
.Tap(e => // set concurrency version for optimistic concurrency check
61-
{
62-
e.ConcurrencyVersion = Guid.Parse(request.Model.ConcurrencyVersion);
63-
})
55+
// STEP 3 - Apply changes to Aggregate from request model
56+
.Bind(e => this.UpdateAggregate(e, request.Model))
6457

6558
// STEP 4 — Save updated Aggregate to repository
6659
.BindAsync(async (e, ct) =>
@@ -69,65 +62,74 @@ await repository.UpdateResultAsync(e, ct), cancellationToken)
6962
// STEP 5 — Side effects (audit/logging)
7063
.Log(logger, "AUDIT - Customer {Id} updated for {Email}", r => [r.Value.Id, r.Value.Email.Value])
7164

72-
// STEP 6 — Map updated Aggregate Model
65+
// STEP 6 — Map updated Aggregate -> Model
7366
.MapResult<Customer, CustomerModel>(mapper)
74-
.Log(logger, "Entity mapped to {@Model}", r => [r.Value]);
67+
.Log(logger, "Aggregate mapped to {@Model}", r => [r.Value]);
68+
69+
/// <summary>
70+
/// Updates the customer's basic properties (name, email, birth date, status).
71+
/// </summary>
72+
/// <param name="customer">The customer aggregate to update.</param>
73+
/// <param name="model">The customer model containing the updated values.</param>
74+
/// <returns>The updated customer wrapped in a Result.</returns>
75+
private Result<Customer> UpdateAggregate(Customer customer, CustomerModel model) =>
76+
// Setup the customer update chain.
77+
Result<Customer>.Success(customer)
78+
.Bind(e => e.ChangeName(model.FirstName, model.LastName))
79+
.Bind(e => e.ChangeEmail(model.Email))
80+
.Bind(e => e.ChangeBirthDate(model.DateOfBirth))
81+
.Bind(e => e.ChangeStatus(model.Status))
82+
.Bind(e => this.ChangeAddresses(customer, model))
83+
.Tap(e => e.ConcurrencyVersion = Guid.Parse(model.ConcurrencyVersion)); // set concurrency version for optimistic concurrency check
7584

7685
/// <summary>
7786
/// Processes address changes by comparing the specified addresses with existing ones.
7887
/// Removes Customer addresses not in the specified addresses, adds new addresses and updates existing addresses.
7988
/// </summary>
8089
/// <param name="customer">The customer aggregate to update.</param>
81-
/// <param name="addressModels">The addresses from the update request.</param>
90+
/// <param name="model">The customer model containing the updated values.</param>
8291
/// <returns>The updated customer wrapped in a Result.</returns>
83-
private Result<Customer> UpdateAddresses(Customer customer, List<CustomerAddressModel> addressModels)
92+
private Result<Customer> ChangeAddresses(Customer customer, CustomerModel model)
8493
{
85-
addressModels ??= [];
94+
// Setup the address update chain.
95+
return Result<Customer>.Success(customer)
96+
.When(_ => model.Addresses.SafeAny(), r => r
97+
.Bind(c => RemoveMissing(c, model.Addresses))
98+
.Bind(c => AddOrChange(c, model.Addresses))
99+
.Bind(c => SetPrimary(c, model.Addresses)));
86100

87-
// Extract valid address IDs from request using LINQ fluent style
88-
var addressIds = addressModels
89-
.Where(m => !string.IsNullOrWhiteSpace(m.Id))
90-
.Select(m => AddressId.Create(m.Id)).ToList();
91-
92-
// Remove obsolete addresses - find and return first failure if any
93-
var removeResult = customer.Addresses
94-
.Select(a => a.Id).Except(addressIds)
95-
.Select(customer.RemoveAddress).FirstOrDefault(r => r.IsFailure).Unwrap(); // TODO: use .Flatten()
96-
97-
// Early return on first failure using fluent When extension
98-
if (removeResult.IsFailure)
101+
// Removes addresses from the customer that are not present in the provided address models.
102+
Result<Customer> RemoveMissing(Customer customer, List<CustomerAddressModel> addressModels)
99103
{
100-
return removeResult;
104+
var keepIds = addressModels
105+
.Where(m => !string.IsNullOrWhiteSpace(m.Id))
106+
.Select(m => AddressId.Create(m.Id)).ToList();
107+
var removeIds = customer.Addresses.Select(a => a.Id).Except(keepIds).ToList();
108+
foreach (var id in removeIds)
109+
{
110+
var result = customer.RemoveAddress(id);
111+
if (result.IsFailure) return result;
112+
}
113+
return Result<Customer>.Success(customer);
101114
}
102115

103-
// Process each address: add new or update existing
104-
foreach (var addressModel in addressModels)
116+
// Processes the provided address models to add new addresses or update existing ones.
117+
Result<Customer> AddOrChange(Customer customer, List<CustomerAddressModel> addressModels)
105118
{
106-
var result = ProcessAddress(customer, addressModel);
107-
if (result.IsFailure)
119+
foreach (var m in addressModels)
108120
{
109-
return result;
121+
var result = string.IsNullOrWhiteSpace(m.Id)
122+
? customer.AddAddress(m.Name, m.Line1, m.Line2, m.PostalCode, m.City, m.Country)
123+
: customer.ChangeAddress(m.Id, m.Name, m.Line1, m.Line2, m.PostalCode, m.City, m.Country);
124+
if (result.IsFailure) return result;
110125
}
126+
return Result<Customer>.Success(customer);
111127
}
112128

113-
// Set primary address if specified
114-
return addressModels
115-
.Find(m => m.IsPrimary)
116-
.Match(
129+
// Sets the primary address of the customer based on the provided address models.
130+
Result<Customer> SetPrimary(Customer customer, List<CustomerAddressModel> addressModels) =>
131+
addressModels.Find(m => m.IsPrimary).Match(
117132
some: m => customer.SetPrimaryAddress(m.Id),
118133
none: () => Result<Customer>.Success(customer));
119-
120-
Result<Customer> ProcessAddress(Customer customer, CustomerAddressModel model) =>
121-
string.IsNullOrWhiteSpace(model.Id)
122-
? customer.AddAddress(
123-
model.Name, model.Line1, model.Line2,
124-
model.PostalCode, model.City, model.Country)
125-
: customer.Addresses
126-
.Find(a => a.Id == AddressId.Create(model.Id))
127-
.Match(
128-
some: _ => customer.ChangeAddress(
129-
model.Id, model.Name, model.Line1, model.Line2,
130-
model.PostalCode, model.City, model.Country),
131-
none: () => Result<Customer>.Success(customer));
132134
}
133135
}

src/Modules/CoreModule/CoreModule.Application/Commands/CustomerUpdateStatusCommandHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,6 @@ await repository.UpdateResultAsync(e, ct), cancellationToken)
3636
// STEP 4 — Side effects (audit/logging)
3737
.Log(logger, "AUDIT - Customer {Id} status updated for {Email}", r => [r.Value.Id, r.Value.Email.Value])
3838

39-
// STEP 5 — Map updated Aggregate Model
39+
// STEP 5 — Map updated Aggregate -> Model
4040
.MapResult<Customer, CustomerModel>(mapper);
4141
}

src/Modules/CoreModule/CoreModule.Application/Queries/CustomerFindAllQueryHandler.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ namespace BridgingIT.DevKit.Examples.GettingStarted.Modules.CoreModule.Applicati
1919
/// - Configured with retry (<see cref="HandlerRetryAttribute"/>) for transient failures.
2020
/// - Configured with timeout (<see cref="HandlerTimeoutAttribute"/>) to bound execution.
2121
/// - Uses <see cref="IGenericRepository{Customer}"/> for persistence access.
22-
/// - Uses <see cref="IMapper"/> (Mapster abstraction) for domain DTO transformations.
22+
/// - Uses <see cref="IMapper"/> (Mapster abstraction) for domain -> DTO transformations.
2323
/// </remarks>
2424
// [HandlerRetry(2, 100)] // retry twice with 100ms delay between retries
2525
// [HandlerTimeout(500)] // enforce max 500ms execution per request
@@ -49,7 +49,7 @@ protected override async Task<Result<IEnumerable<CustomerModel>>> HandleAsync(
4949
// Side effects (audit/logging)
5050
.Log(logger, "AUDIT - Customers retrieved (count: {Count}, filter: {@Filter})", r => [r.Value.Count(), request.Filter])
5151

52-
// Map retrieved Aggregates Models
52+
// Map retrieved Aggregates -> Models
5353
.Map(mapper.Map<Customer, CustomerModel>);
5454
}
5555
}

src/Modules/CoreModule/CoreModule.Application/Queries/CustomerFindOneQueryHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,6 @@ await repository.FindOneResultAsync(CustomerId.Create(request.Id), cancellationT
4646
// Side effects (audit/logging)
4747
.Log(logger, "AUDIT - Customer {CustomerId} retrieved", r => [r.Value.Id])
4848

49-
// Map retrieved Aggregate Model
49+
// Map retrieved Aggregate -> Model
5050
.MapResult<Customer, CustomerModel>(mapper);
5151
}

src/Modules/CoreModule/CoreModule.Domain/Model/CustomerAggregate/Address.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ private Address(string name, string line1, string line2, string postalCode, stri
8484
/// <param name="city">The city name (required).</param>
8585
/// <param name="country">The country name (required).</param>
8686
/// <param name="isPrimary">Indicates whether this is the primary address (default: false).</param>
87-
/// <returns>A new <see cref="Address"/> instance wrapped in a <see cref="Result{T}"/>.</returns>
87+
/// <returns>A new <see cref="Address"/> instance wrapped in a Result.</returns>
8888
public static Result<Address> Create(string name, string line1, string line2, string postalCode, string city, string country, bool isPrimary = false)
8989
{
9090
return Result<Address>.Success()
@@ -99,7 +99,7 @@ public static Result<Address> Create(string name, string line1, string line2, st
9999
/// Changes the name/label of the address if different from the current value.
100100
/// </summary>
101101
/// <param name="name">The new name/label (required).</param>
102-
/// <returns>The current <see cref="Address"/> instance for chaining.</returns>
102+
/// <returns>The updated <see cref="Address"/> wrapped in a Result.</returns>
103103
public Result<Address> ChangeName(string name)
104104
{
105105
return this.Change()
@@ -112,7 +112,7 @@ public Result<Address> ChangeName(string name)
112112
/// Changes the first line of the address if different from the current value.
113113
/// </summary>
114114
/// <param name="line1">The new first line (required).</param>
115-
/// <returns>The current <see cref="Address"/> instance for chaining.</returns>
115+
/// <returns>The updated <see cref="Address"/> wrapped in a Result.</returns>
116116
public Result<Address> ChangeLine1(string line1)
117117
{
118118
return this.Change()
@@ -125,7 +125,7 @@ public Result<Address> ChangeLine1(string line1)
125125
/// Changes the second line of the address if different from the current value.
126126
/// </summary>
127127
/// <param name="line2">The new second line (optional).</param>
128-
/// <returns>The current <see cref="Address"/> instance for chaining.</returns>
128+
/// <returns>The updated <see cref="Address"/> wrapped in a Result.</returns>
129129
public Result<Address> ChangeLine2(string line2)
130130
{
131131
return this.Change()
@@ -137,7 +137,7 @@ public Result<Address> ChangeLine2(string line2)
137137
/// Changes the postal code of the address if different from the current value.
138138
/// </summary>
139139
/// <param name="postalCode">The new postal code (optional).</param>
140-
/// <returns>The current <see cref="Address"/> instance for chaining.</returns>
140+
/// <returns>The updated <see cref="Address"/> wrapped in a Result.</returns>
141141
public Result<Address> ChangePostalCode(string postalCode)
142142
{
143143
return this.Change()
@@ -149,7 +149,7 @@ public Result<Address> ChangePostalCode(string postalCode)
149149
/// Changes the city of the address if different from the current value.
150150
/// </summary>
151151
/// <param name="city">The new city (required).</param>
152-
/// <returns>The current <see cref="Address"/> instance for chaining.</returns>
152+
/// <returns>The updated <see cref="Address"/> wrapped in a Result.</returns>
153153
public Result<Address> ChangeCity(string city)
154154
{
155155
return this.Change()
@@ -162,7 +162,7 @@ public Result<Address> ChangeCity(string city)
162162
/// Changes the country of the address if different from the current value.
163163
/// </summary>
164164
/// <param name="country">The new country (required).</param>
165-
/// <returns>The current <see cref="Address"/> instance for chaining.</returns>
165+
/// <returns>The updated <see cref="Address"/> wrapped in a Result.</returns>
166166
public Result<Address> ChangeCountry(string country)
167167
{
168168
return this.Change()
@@ -175,7 +175,7 @@ public Result<Address> ChangeCountry(string country)
175175
/// Sets whether this address is the primary address.
176176
/// </summary>
177177
/// <param name="isPrimary">True to set as primary; false otherwise.</param>
178-
/// <returns>The current <see cref="Address"/> instance for chaining.</returns>
178+
/// <returns>The updated <see cref="Address"/> wrapped in a Result.</returns>
179179
public Result<Address> SetPrimary(bool isPrimary)
180180
{
181181
return this.Change()

0 commit comments

Comments
 (0)