Add Value Objects

This commit is contained in:
amir.gholami 2023-05-21 19:29:06 +03:30
parent 0d8f52b573
commit 5c5be8eef8
15 changed files with 174 additions and 33 deletions

View File

@ -7,10 +7,9 @@ using Ardalis.GuardClauses;
using BuildingBlocks.Core.CQRS; using BuildingBlocks.Core.CQRS;
using BuildingBlocks.Core.Event; using BuildingBlocks.Core.Event;
using BuildingBlocks.Web; using BuildingBlocks.Web;
using Exceptions;
using Models;
using Data; using Data;
using Duende.IdentityServer.EntityFramework.Entities; using Duende.IdentityServer.EntityFramework.Entities;
using Exceptions;
using FluentValidation; using FluentValidation;
using MapsterMapper; using MapsterMapper;
using MassTransit; using MassTransit;
@ -19,6 +18,8 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Models;
using Models.ValueObjects;
public record CreateAircraft(string Name, string Model, int ManufacturingYear) : ICommand<CreateAircraftResult>, public record CreateAircraft(string Name, string Model, int ManufacturingYear) : ICommand<CreateAircraftResult>,
IInternalCommand IInternalCommand
@ -96,7 +97,7 @@ internal class CreateAircraftHandler : IRequestHandler<CreateAircraft, CreateAir
throw new AircraftAlreadyExistException(); throw new AircraftAlreadyExistException();
} }
var aircraftEntity = Aircraft.Create(request.Id, request.Name, request.Model, request.ManufacturingYear); var aircraftEntity = Aircraft.Create(request.Id, NameValue.Of(request.Name), ModelValue.Of(request.Model), ManufacturingYearValue.Of(request.ManufacturingYear));
var newAircraft = (await _flightDbContext.Aircraft.AddAsync(aircraftEntity, cancellationToken))?.Entity; var newAircraft = (await _flightDbContext.Aircraft.AddAsync(aircraftEntity, cancellationToken))?.Entity;

View File

@ -4,14 +4,15 @@ namespace Flight.Aircrafts.Models;
using System; using System;
using Features.CreatingAircraft.V1; using Features.CreatingAircraft.V1;
using ValueObjects;
public record Aircraft : Aggregate<Guid> public record Aircraft : Aggregate<Guid>
{ {
public string Name { get; private set; } public NameValue Name { get; private set; }
public string Model { get; private set; } public ModelValue Model { get; private set; }
public int ManufacturingYear { get; private set; } public ManufacturingYearValue ManufacturingYear { get; private set; }
public static Aircraft Create(Guid id, string name, string model, int manufacturingYear, bool isDeleted = false) public static Aircraft Create(Guid id, NameValue name, ModelValue model, ManufacturingYearValue manufacturingYear, bool isDeleted = false)
{ {
var aircraft = new Aircraft var aircraft = new Aircraft
{ {

View File

@ -0,0 +1,18 @@
namespace Flight.Aircrafts.Models.ValueObjects;
using System;
public record ManufacturingYearValue : GenericValueObject<int>
{
public ManufacturingYearValue(int value) : base(value)
{
if (value < 1900 || value > DateTime.Now.Year)
{
throw new ArgumentException("Manufacturing year is invalid.");
}
}
public static ManufacturingYearValue Of(int value)
{
return new ManufacturingYearValue(value);
}
}

View File

@ -0,0 +1,17 @@
namespace Flight.Aircrafts.Models.ValueObjects;
using System;
public record ModelValue : GenericValueObject<string>
{
public ModelValue(string value) : base(value)
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("Model cannot be empty or whitespace.");
}
}
public static ModelValue Of(string value)
{
return new ModelValue(value);
}
}

View File

@ -0,0 +1,18 @@
namespace Flight.Aircrafts.Models.ValueObjects;
using System;
public record NameValue : GenericValueObject<string>
{
public NameValue(string value) : base(value)
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("Name cannot be empty or whitespace.");
}
}
public static NameValue Of(string value)
{
return new NameValue(value);
}
}

View File

@ -1,9 +1,10 @@
namespace Flight.Data.Seed; namespace Flight.Data.Seed;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Aircrafts.Models; using Aircrafts.Models;
using Aircrafts.Models.ValueObjects;
using Airports.Models; using Airports.Models;
using Flights.Models; using Flights.Models;
using MassTransit; using MassTransit;
@ -27,9 +28,9 @@ public static class InitialData
Aircrafts = new List<Aircraft> Aircrafts = new List<Aircraft>
{ {
Aircraft.Create(new Guid("3c5c0000-97c6-fc34-fcd3-08db322230c8"), "Boeing 737", "B737", 2005), Aircraft.Create(new Guid("3c5c0000-97c6-fc34-fcd3-08db322230c8"), NameValue.Of("Boeing 737"), ModelValue.Of("B737"), ManufacturingYearValue.Of(2005)),
Aircraft.Create(new Guid("3c5c0000-97c6-fc34-2e04-08db322230c9"), "Airbus 300", "A300", 2000), Aircraft.Create(new Guid("3c5c0000-97c6-fc34-2e04-08db322230c9"), NameValue.Of("Airbus 300"), ModelValue.Of("A300"), ManufacturingYearValue.Of(2000)),
Aircraft.Create(new Guid("3c5c0000-97c6-fc34-2e11-08db322230c9"), "Airbus 320", "A320", 2003) Aircraft.Create(new Guid("3c5c0000-97c6-fc34-2e11-08db322230c9"), NameValue.Of("Airbus 320"), ModelValue.Of("A320"), ManufacturingYearValue.Of(2003))
}; };

View File

@ -0,0 +1,13 @@
namespace Flight;
public record GenericValueObject<T>(T Value)
{
public override string ToString()
{
return Value.ToString();
}
public static implicit operator T(GenericValueObject<T> valueObject)
{
return valueObject.Value;
}
}

View File

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Flight.Data; using Flight.Data;
using Flight.Flights.Enums; using Flight.Flights.Enums;
@ -7,6 +7,7 @@ using Microsoft.EntityFrameworkCore;
namespace Unit.Test.Common; namespace Unit.Test.Common;
using global::Flight.Aircrafts.Models.ValueObjects;
using MassTransit; using MassTransit;
public static class DbContextFactory public static class DbContextFactory
@ -45,9 +46,9 @@ public static class DbContextFactory
var aircrafts = new List<global::Flight.Aircrafts.Models.Aircraft> var aircrafts = new List<global::Flight.Aircrafts.Models.Aircraft>
{ {
global::Flight.Aircrafts.Models.Aircraft.Create(_aircraft1, "Boeing 737", "B737", 2005), global::Flight.Aircrafts.Models.Aircraft.Create(_aircraft1, NameValue.Of("Boeing 737"), ModelValue.Of("B737"), ManufacturingYearValue.Of(2005)),
global::Flight.Aircrafts.Models.Aircraft.Create(_aircraft2, "Airbus 300", "A300", 2000), global::Flight.Aircrafts.Models.Aircraft.Create(_aircraft2, NameValue.Of("Airbus 300"), ModelValue.Of("A300"), ManufacturingYearValue.Of(2000)),
global::Flight.Aircrafts.Models.Aircraft.Create(_aircraft3, "Airbus 320", "A320", 2003) global::Flight.Aircrafts.Models.Aircraft.Create(_aircraft3, NameValue.Of("Airbus 320"), ModelValue.Of("A320"), ManufacturingYearValue.Of(2003))
}; };
context.Aircraft.AddRange(aircrafts); context.Aircraft.AddRange(aircrafts);

View File

@ -5,12 +5,13 @@ using BuildingBlocks.Contracts.EventBus.Messages;
using BuildingBlocks.Core; using BuildingBlocks.Core;
using BuildingBlocks.Core.Event; using BuildingBlocks.Core.Event;
using BuildingBlocks.Web; using BuildingBlocks.Web;
using Data;
using Humanizer; using Humanizer;
using MassTransit; using MassTransit;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Data; using Passenger.Passengers.Models.ValueObjects;
public class RegisterNewUserHandler : IConsumer<UserCreated> public class RegisterNewUserHandler : IConsumer<UserCreated>
{ {
@ -44,8 +45,8 @@ public class RegisterNewUserHandler : IConsumer<UserCreated>
return; return;
} }
var passenger = Passengers.Models.Passenger.Create(NewId.NextGuid(), context.Message.Name, var passenger = Passengers.Models.Passenger.Create(NewId.NextGuid(), NameValue.Of(context.Message.Name),
context.Message.PassportNumber); PassportNumberValue.Of(context.Message.PassportNumber));
await _passengerDbContext.AddAsync(passenger); await _passengerDbContext.AddAsync(passenger);

View File

@ -4,18 +4,19 @@ using Ardalis.GuardClauses;
using BuildingBlocks.Core.CQRS; using BuildingBlocks.Core.CQRS;
using BuildingBlocks.Core.Event; using BuildingBlocks.Core.Event;
using BuildingBlocks.Web; using BuildingBlocks.Web;
using Exceptions;
using FluentValidation;
using MapsterMapper;
using Microsoft.EntityFrameworkCore;
using Data; using Data;
using Dtos; using Dtos;
using Duende.IdentityServer.EntityFramework.Entities; using Duende.IdentityServer.EntityFramework.Entities;
using Exceptions;
using FluentValidation;
using MapsterMapper;
using MassTransit; using MassTransit;
using MediatR; using MediatR;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Routing;
using Microsoft.EntityFrameworkCore;
using Passenger.Passengers.Models.ValueObjects;
public record CompleteRegisterPassenger public record CompleteRegisterPassenger
(string PassportNumber, Enums.PassengerType PassengerType, int Age) : ICommand<CompleteRegisterPassengerResult>, (string PassportNumber, Enums.PassengerType PassengerType, int Age) : ICommand<CompleteRegisterPassengerResult>,
@ -104,7 +105,7 @@ internal class CompleteRegisterPassengerCommandHandler : ICommandHandler<Complet
} }
var passengerEntity = passenger.CompleteRegistrationPassenger(passenger.Id, passenger.Name, var passengerEntity = passenger.CompleteRegistrationPassenger(passenger.Id, passenger.Name,
passenger.PassportNumber, request.PassengerType, request.Age); passenger.PassportNumber, request.PassengerType, AgeValue.Of(request.Age));
var updatePassenger = _passengerDbContext.Passengers.Update(passengerEntity); var updatePassenger = _passengerDbContext.Passengers.Update(passengerEntity);

View File

@ -3,24 +3,25 @@ using BuildingBlocks.Core.Model;
namespace Passenger.Passengers.Models; namespace Passenger.Passengers.Models;
using Features.CompletingRegisterPassenger.V1; using Features.CompletingRegisterPassenger.V1;
using global::Passenger.Passengers.Models.ValueObjects;
using Identity.Consumers.RegisteringNewUser.V1; using Identity.Consumers.RegisteringNewUser.V1;
public record Passenger : Aggregate<Guid> public record Passenger : Aggregate<Guid>
{ {
public Passenger CompleteRegistrationPassenger(Guid id, string name, string passportNumber, Enums.PassengerType passengerType, int age, bool isDeleted = false) public Passenger CompleteRegistrationPassenger(Guid id, NameValue name, PassportNumberValue passportNumber, Enums.PassengerType passengerType, AgeValue age, bool isDeleted = false)
{ {
var passenger = new Passenger var passenger = new Passenger
{ {
Id = id,
Name = name, Name = name,
PassportNumber = passportNumber, PassportNumber = passportNumber,
PassengerType = passengerType, PassengerType = passengerType,
Age = age, Age = age,
Id = id,
IsDeleted = isDeleted IsDeleted = isDeleted
}; };
var @event = new PassengerRegistrationCompletedDomainEvent(passenger.Id, passenger.Name, passenger.PassportNumber, var @event = new PassengerRegistrationCompletedDomainEvent(passenger.Id, passenger.Name, passenger.PassportNumber,
passenger.PassengerType, passenger.Age, passenger.IsDeleted); passenger.PassengerType, passenger.Age.Value, passenger.IsDeleted);
passenger.AddDomainEvent(@event); passenger.AddDomainEvent(@event);
@ -28,7 +29,7 @@ public record Passenger : Aggregate<Guid>
} }
public static Passenger Create(Guid id, string name, string passportNumber, bool isDeleted = false) public static Passenger Create(Guid id, NameValue name, PassportNumberValue passportNumber, bool isDeleted = false)
{ {
var passenger = new Passenger { Id = id, Name = name, PassportNumber = passportNumber, IsDeleted = isDeleted }; var passenger = new Passenger { Id = id, Name = name, PassportNumber = passportNumber, IsDeleted = isDeleted };
@ -40,8 +41,8 @@ public record Passenger : Aggregate<Guid>
} }
public string PassportNumber { get; private set; } public PassportNumberValue PassportNumber { get; private set; }
public string Name { get; private set; } public NameValue Name { get; private set; }
public Enums.PassengerType PassengerType { get; private set; } public Enums.PassengerType PassengerType { get; private set; }
public int Age { get; private set; } public AgeValue Age { get; private set; }
} }

View File

@ -0,0 +1,18 @@
namespace Passenger.Passengers.Models.ValueObjects;
using System;
public record AgeValue : GenericValueObject<int>
{
public AgeValue(int value) : base(value)
{
if (value < 0)
{
throw new ArgumentException("Age cannot be negative.");
}
Value = value;
}
public static AgeValue Of(int value)
{
return new AgeValue(value);
}
}

View File

@ -0,0 +1,13 @@
namespace Passenger.Passengers.Models.ValueObjects;
public record GenericValueObject<T>(T Value)
{
public override string ToString()
{
return Value.ToString();
}
public static implicit operator T(GenericValueObject<T> valueObject)
{
return valueObject.Value;
}
}

View File

@ -0,0 +1,18 @@
namespace Passenger.Passengers.Models.ValueObjects;
using System;
public record NameValue : GenericValueObject<string>
{
public NameValue(string value) : base(value)
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("Name cannot be empty or whitespace.");
}
Value = value;
}
public static NameValue Of(string value)
{
return new NameValue(value);
}
}

View File

@ -0,0 +1,19 @@
namespace Passenger.Passengers.Models.ValueObjects;
using System;
public record PassportNumberValue : GenericValueObject<string>
{
public PassportNumberValue(string value) : base(value)
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("Passport number cannot be empty or whitespace.");
}
Value = value;
}
public static PassportNumberValue Of(string value)
{
return new PassportNumberValue(value);
}
}