(文章目录) 前言 1.什么是CQRS模式 CQRS 是一种与领域驱动设计 (DDD) 和事件溯源相关的架构模式,本质上是一种读写逻辑分离的机制。 CQRS可以有两种实现方式。 1、CQ两端数据库共享,只
(文章目录)
前言
1.什么是CQRS模式
CQRS 是一种与领域驱动设计 (DDD) 和事件溯源相关的架构模式,本质上是一种读写逻辑分离的机制。
CQRS可以有两种实现方式。
1、CQ两端数据库共享,只是在上层代码上分离。
这样做的好处是可以让我们的代码读写分离,更容易维护,而且不存在CQ两端的数据一致性问题, 因为是共享一个数据库的。
2、CQ两端不仅代码分离,数据库也分离,然后Q端数据由C端同步过来。
同步方式有两种:同步或异步,如果需要CQ两端的强一致性,则需要用同步;如果能接受CQ两端数据的最终一致性,则可以使用异步。
C端可以采用EventSourcing(简称ES)模式,所有C端的最新数据全部用DomainEvent表达即可。
而要查询显示用的数据,则从Q端的ReadDB(关系型数据库)查询即可。
2.中介者模式
中介者模式属于行为型模式,它包装了一系列对象相互作用的方式,使得这些对象不必相互明显作用,从而使它们可以松散耦合。
当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用,保证这些作用可以彼此独立的变化。
具体二十三种设计模式可以查看这个专题:https://blog.csdn.net/aa2528877987/article/details/108290229
3.MediatR
MediatR是一个实现中介者模式的类库,可以帮我们轻松的实现CQRS 。
MediatR有两种功能,一种是单播消息传播(请求/响应消息),就是一对一消息传递,这个就比较适合CQRS模式;另一种是多播消息传递(发布通知),消息分发给多个应用,这种适用于消息订阅。下面简单介绍一下这两种方式的使用。
一、基于MediatR的CQRS模式
1.添加包
dotnet add package MediatR
dotnet add package MediatR.Extensions.Microsoft.DependencyInjection
2.MediatR单播消息模式使用
2.1 创建消息对象
1、请求对象
命令对象
//命令对象,也就是增加或者修改传入的模型,正常情况下可以增加验证的功能
//请求需要继承IRequest<ResponseModel>,泛型里面是相应类
public class MakeCustomerRequestModel : IRequest<MakeCustomerResponseModel>
{
public Guid CustomerId { get; set; }
public string CustomerName { get; set; }
public Guid BlongId { get; set; }
public int Quantity { get; set; }
public double Amount { get; set; }
public string Phone { get; set; }
public DateTime CreatTime { get; set; }
}
查询对象
//查询对象,可以通过id等去查询
//请求需要继承IRequest<ResponseModel>,泛型里面是相应类
public class GetCustomerByIdRequestModel : IRequest<GetCustomerByIdResponseModel>
{
public Guid CustomerId { get; set; }
}
2、响应对象
命令对象
//命令对象,返回主键ID,和是否查询成功
public class MakeCustomerResponseModel
{
public bool IsSuccess { get; set; }
public Guid CustomerId { get; set; }
}
查询对象
//查询对象,返回查询的数据,刚好与前面相反
public class GetCustomerByIdResponseModel
{
public Guid CustomerId { get; set; }
public string CustomerName { get; set; }
public Guid BlongId { get; set; }
public int Quantity { get; set; }
public double Amount { get; set; }
public string Phone { get; set; }
public DateTime CreatTime { get; set; }
}
2.2 创建消息处理器Handlers
命令对象
//命令处理,需要继承IRequestHandler泛型,和实现Handle方法,如下
public class MakeCustomerCommandHandler : IRequestHandler<MakeCustomerRequestModel, MakeCustomerResponseModel>
{
public Task<MakeCustomerResponseModel> Handle(MakeCustomerRequestModel request, CancellationToken cancellationToken)
{
var result = new MakeCustomerResponseModel
{
IsSuccess = true,
CustomerId = new Guid("4ED8843E-7718-40D1-B8E0-B813FE4E0A68")
};
// 业务逻辑
return Task.FromResult(result);
}
}
查询对象
//命令处理,需要继承IRequestHandler泛型,和实现Handle方法,如下
public class GetCustomerByIdQueryHandlers : IRequestHandler<GetCustomerByIdRequestModel, GetCustomerByIdResponseModel>
{
public Task<GetCustomerByIdResponseModel> Handle(GetCustomerByIdRequestModel request, CancellationToken cancellationToken)
{
var orderDetails = new GetCustomerByIdResponseModel();
// 业务逻辑
return Task.FromResult(orderDetails);
}
}
2.3 注入使用
1、注入
#region 添加MediatR
builder.Services.AddMediatR(Assembly.GetExecutingAssembly());
#endregion
2、使用
[Route("[controller]/[action]")]
[ApiController]
public class CustomerController : ControllerBase
{
private readonly IMediator _mediator;
public CustomerController(IMediator mediator)
{
_mediator = mediator;
}
[HttpPost]
public IActionResult MakeCustomer([FromBody] MakeCustomerRequestModel requestModel)
{
var response = _mediator.Send(requestModel).Result;
return Ok(response);
}
[HttpGet]
public IActionResult CustomerDetails(Guid id)
{
var response = _mediator.Send(new GetCustomerByIdRequestModel { CustomerId = id }).Result;
return Ok(response);
}
}
2、效果
命令对象 查询对象
3.MediatR多消息模式使用
3.1 创建消息对象
public class GeneralNotificationModel : INotification
{
public string Title { get; set; }
public string Content { get; set; }
public GeneralNotificationModel(string title, string content)
{
Title = title;
Content = content;
}
}
3.2 创建消息处理器Handlers
public class GeneralNotificationHandler : INotificationHandler<GeneralNotificationModel>
{
public Task Handle(GeneralNotificationModel notification, CancellationToken cancellationToken)
{
Console.WriteLine($"{notification.Title}:{notification.Content}");
return Task.CompletedTask;
}
}
public class LogHandler : INotificationHandler<GeneralNotificationModel>
{
private readonly ILogger<LogHandler> _logger;
public LogHandler(ILogger<LogHandler> logger)
{
_logger = logger;
}
public Task Handle(GeneralNotificationModel notification, CancellationToken cancellationToken)
{
_logger.LogInformation($"{notification.Title}:{notification.Content}");
return Task.CompletedTask;
}
}
3.3 注入使用
public class MakeOrderCommandHandler : IRequestHandler<MakeOrderRequestModel,MakeOrderResponseModel>
{
private readonly IMediator _mediator;
public MakeOrderCommandHandler(IMediator mediator)
{
_mediator = mediator;
}
public Task<MakeOrderResponseModel> Handle(MakeOrderRequestModel request, CancellationToken cancellationToken)
{
var result = new MakeOrderResponseModel
{
IsSuccess = true,
OrderId = new Guid("53d26807-ad70-4449-8479-024c54eb2020")
};
//发布
_mediator.Publish(new GeneralNotificationModel("已下单", result.OrderId.ToString()), cancellationToken);
return Task.FromResult(result);
}
}