欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > IT业 > (二)毛子整洁架构(CQRS/Dapper/DomianEvent Handler)

(二)毛子整洁架构(CQRS/Dapper/DomianEvent Handler)

2025/5/8 20:47:05 来源:https://blog.csdn.net/weixin_42067536/article/details/147743273  浏览:    关键词:(二)毛子整洁架构(CQRS/Dapper/DomianEvent Handler)

文章目录

  • 项目地址
  • 一、Application 层
    • 1.1 定义CQRS的接口以及其他服务
      • 1. Command
      • 2. IQuery查询
      • 3. 当前时间服务接口
      • 4. 邮件发送服务接口
    • 1.2 ReserveBooking Command
      • 1. 处理传入的参数
      • 2. ReserveBookingCommandHandler
      • 3. BookingReservedDomainEvent
    • 1.3 GetBooking Query
      • 1. 创建Dapper的链接接口
      • 2. Query
      • 3. QueryHandler


项目地址

  • 教程作者:
  • 教程地址:
  • 代码仓库地址:
  • 所用到的框架和插件:
dbt 
airflow

一、Application 层

1.1 定义CQRS的接口以及其他服务

在这里插入图片描述

1. Command

  • 用于处理除查询以外的
  1. ICommand.cs
using Bookify.Domain.Abstractions;
using MediatR;
namespace Bookify.Application.Abstractions.Messaging;
//无返回值的命令
public interface ICommand : IRequest<Result>
{
}
//返回一个TReponse的命令
public interface ICommand<TReponse> : IRequest<Result<TReponse>>
{
}
  1. ICommandHandler.cs
namespace Bookify.Application.Abstractions.Messaging;
public interface ICommandHandler<TCommand> : IRequestHandler<TCommand, Result>where TCommand : ICommand
{
}public interface ICommandHandler<TCommand, TResponse> : IRequestHandler<TCommand, Result<TResponse>>where TCommand : ICommand<TResponse>
{
}

2. IQuery查询

  • 用于查询
    IQuery.cs
using Bookify.Domain.Abstractions;
using MediatR;
namespace Bookify.Application.Abstractions.Messaging;
public interface IQuery<TResponse> : IRequest<Result<TResponse>>
{
}
  • IQueryHandler.cs
using Bookify.Domain.Abstractions;
using MediatR;
namespace Bookify.Application.Abstractions.Messaging;
public interface IQueryHandler<TQuery, TResponse> : IRequestHandler<TQuery, Result<TResponse>>where TQuery : IQuery<TResponse>
{
}

3. 当前时间服务接口

  • 用于提供当前时间
namespace Bookify.Application.Abstractions.Clock;public interface IDateTimeProvider
{DateTime UtcNow { get; }
}

4. 邮件发送服务接口

  • 发送邮件的服务
namespace Bookify.Application.Abstractions.Email;
public interface IEmailService
{Task SendAsync(Domain.Users.Email recipient, string subject, string body);
}

1.2 ReserveBooking Command

在这里插入图片描述

1. 处理传入的参数

  • ReserveBookingCommand.cs:返回值是Guid,参数时4个
using Bookify.Application.Abstractions.Messaging;
namespace Bookify.Application.Bookings.ReserveBooking;
public record ReserveBookingCommand(Guid ApartmentId,Guid UserId,DateOnly StartDate,DateOnly EndDate) : ICommand<Guid>;

2. ReserveBookingCommandHandler

  • 用于保存预定的处理方法
internal sealed class ReserveBookingCommandHandler : ICommandHandler<ReserveBookingCommand, Guid>
{private readonly IUserRepository _userRepository;private readonly IApartmentRepository _apartmentRepository;private readonly IBookingRepository _bookingRepository;private readonly IUnitOfWork _unitOfWork;private readonly PricingService _pricingService;private readonly IDateTimeProvider _dateTimeProvider;public ReserveBookingCommandHandler(IUserRepository userRepository,IApartmentRepository apartmentRepository,IBookingRepository bookingRepository,IUnitOfWork unitOfWork,PricingService pricingService,IDateTimeProvider dateTimeProvider){_userRepository = userRepository;_apartmentRepository = apartmentRepository;_bookingRepository = bookingRepository;_unitOfWork = unitOfWork;_pricingService = pricingService;_dateTimeProvider = dateTimeProvider;}public async Task<Result<Guid>> Handle(ReserveBookingCommand request, CancellationToken cancellationToken){// Check if the user existsUser? user = await _userRepository.GetByIdAsync(request.UserId, cancellationToken);if (user is null){return Result.Failure<Guid>(UserErrors.NotFound);}// Check if the apartment existsApartment? apartment = await _apartmentRepository.GetByIdAsync(request.ApartmentId, cancellationToken);if (apartment is null){return Result.Failure<Guid>(ApartmentErrors.NotFound);}//创建预定时间段var duration = DateRange.Create(request.StartDate, request.EndDate);// Check if the booking duration is validif (await _bookingRepository.IsOverlappingAsync(apartment, duration, cancellationToken)){return Result.Failure<Guid>(BookingErrors.Overlap);}var booking = Booking.Reserve(apartment,user.Id,duration,_dateTimeProvider.UtcNow,_pricingService);//添加booking_bookingRepository.Add(booking);//保存await _unitOfWork.SaveChangesAsync(cancellationToken);return booking.Id;}
}

3. BookingReservedDomainEvent

  • 处理 BookingReservedDomainEvent 事件的逻辑,这里只是一个处理的函数,并没有自动执行,只有当发布了事件之后,才会触发
namespace Bookify.Application.Bookings.ReserveBooking;/// 处理 BookingReservedDomainEvent 事件
internal sealed class BookingReservedDomainEventHandler : INotificationHandler<BookingReservedDomainEvent>
{private readonly IBookingRepository _bookingRepository;private readonly IUserRepository _userRepository;private readonly IEmailService _emailService;public BookingReservedDomainEventHandler(IEmailService emailService, IUserRepository userRepository, IBookingRepository bookingRepository){_emailService = emailService;_userRepository = userRepository;_bookingRepository = bookingRepository;}public async Task Handle(BookingReservedDomainEvent notification, CancellationToken cancellationToken){//通过事件里传来的 BookingId 从数据库查出预订信息。Booking? booking = await _bookingRepository.GetByIdAsync(notification.BookingId, cancellationToken);if (booking is null){return;}//根据 booking.UserId 查出用户信息。User? user = await _userRepository.GetByIdAsync(booking.UserId, cancellationToken);if (user is null){return;}//通过用户信息发送邮件。await _emailService.SendAsync(user.Email,"Booking reserved!","You have 10 minutes to confirm this booking");}
}

1.3 GetBooking Query

  • 所有查询,直接使用Dapper

1. 创建Dapper的链接接口

  • 用于连接数据库用
namespace Bookify.Application.Abstractions.Data;
//Dapper链接数据库的工厂接口
public interface ISqlConnectionFactory
{IDbConnection CreateConnection();
}

2. Query

  • GetBookingQuery:传入BookingID,返回BookingResponse
using Bookify.Application.Abstractions.Messaging;
namespace Bookify.Application.Bookings.GetBooking;
public sealed record GetBookingQuery(Guid BookingId) : IQuery<BookingResponse>;
  • BookingResponse.cs
namespace Bookify.Application.Bookings.GetBooking;
public sealed class BookingResponse
{public Guid Id { get; init; }public Guid UserId { get; init; }public Guid ApartmentId { get; init; }    public int Status { get; init; }public decimal PriceAmount { get; init; }public string PriceCurrency { get; init; }public decimal CleaningFeeAmount { get; init; }public string CleaningFeeCurrency { get; init; }public decimal AmenitiesUpChargeAmount { get; init; }public string AmenitiesUpChargeCurrency { get; init; }public decimal TotalPriceAmount { get; init; }public string TotalPriceCurrency { get; init; }public DateOnly DurationStart { get; init; }public DateOnly DurationEnd { get; init; }public DateTime CreatedOnUtc { get; init; }
}

3. QueryHandler

using System.Data;
using Bookify.Application.Abstractions.Data;
using Bookify.Application.Abstractions.Messaging;
using Bookify.Domain.Abstractions;
using Dapper;namespace Bookify.Application.Bookings.GetBooking;
internal sealed class GetBookingQueryHandler : IQueryHandler<GetBookingQuery, BookingResponse>
{private readonly ISqlConnectionFactory _sqlConnectionFactory;public GetBookingQueryHandler(ISqlConnectionFactory sqlConnectionFactory){_sqlConnectionFactory = sqlConnectionFactory;}public async Task<Result<BookingResponse>> Handle(GetBookingQuery request, CancellationToken cancellationToken){//创建数据库连接using IDbConnection connection = _sqlConnectionFactory.CreateConnection();//执行的sqlconst string sql = """SELECTid AS Id,apartment_id AS ApartmentId,user_id AS UserId,status AS Status,price_for_period_amount AS PriceAmount,price_for_period_currency AS PriceCurrency,cleaning_fee_amount AS CleaningFeeAmount,cleaning_fee_currency AS CleaningFeeCurrency,amenities_up_charge_amount AS AmenitiesUpChargeAmount,amenities_up_charge_currency AS AmenitiesUpChargeCurrency,total_price_amount AS TotalPriceAmount,total_price_currency AS TotalPriceCurrency,duration_start AS DurationStart,duration_end AS DurationEnd,created_on_utc AS CreatedOnUtcFROM bookingsWHERE id = @BookingId""";//执行sqlBookingResponse? booking = await connection.QueryFirstOrDefaultAsync<BookingResponse>(sql,new{request.BookingId});return booking;}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词