实现 CQRS 中的 Query 模式
This commit is contained in:
parent
aeefff6c0b
commit
53bf517224
@ -5,6 +5,7 @@ using AutoMapper;
|
||||
using HelloShop.OrderingService.Commands.Orders;
|
||||
using HelloShop.OrderingService.Entities.Orders;
|
||||
using HelloShop.OrderingService.Models.Orders;
|
||||
using HelloShop.OrderingService.Queries;
|
||||
|
||||
namespace HelloShop.OrderingService.AutoMapper
|
||||
{
|
||||
@ -16,6 +17,18 @@ namespace HelloShop.OrderingService.AutoMapper
|
||||
CreateMap<BasketItem, CreateOrderCommand.CreateOrderCommandItem>().ForMember(dest => dest.Units, opt => opt.MapFrom(src => src.Quantity));
|
||||
CreateMap<CreateOrderCommand.CreateOrderCommandItem, OrderItem>();
|
||||
CreateMap<CreateOrderCommand, Address>();
|
||||
|
||||
CreateMap<Order, OrderSummary>().ForMember(dest => dest.OrderId, opt => opt.MapFrom(src => src.Id)).ForMember(dest => dest.Status, opt => opt.MapFrom(src => src.OrderStatus));
|
||||
CreateMap<Order, OrderDetails>()
|
||||
.ForMember(dest => dest.OrderId, opt => opt.MapFrom(src => src.Id))
|
||||
.ForMember(dest => dest.Status, opt => opt.MapFrom(src => src.OrderStatus))
|
||||
.ForMember(dest => dest.Country, opt => opt.MapFrom(src => src.Address.Country))
|
||||
.ForMember(dest => dest.State, opt => opt.MapFrom(src => src.Address.State))
|
||||
.ForMember(dest => dest.City, opt => opt.MapFrom(src => src.Address.City))
|
||||
.ForMember(dest => dest.Street, opt => opt.MapFrom(src => src.Address.Street))
|
||||
.ForMember(dest => dest.ZipCode, opt => opt.MapFrom(src => src.Address.ZipCode));
|
||||
|
||||
CreateMap<OrderItem, OrderDetailsItem>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ using AutoMapper;
|
||||
using HelloShop.OrderingService.Commands;
|
||||
using HelloShop.OrderingService.Commands.Orders;
|
||||
using HelloShop.OrderingService.Models.Orders;
|
||||
using HelloShop.OrderingService.Queries;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@ -62,7 +63,6 @@ public class OrdersController(ILogger<OrdersController> logger, IMediator mediat
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[HttpPut("Cancel/{id}")]
|
||||
public async Task<IActionResult> CancelOrder([FromHeader(Name = "x-request-id")] Guid requestId, int id)
|
||||
{
|
||||
@ -96,4 +96,27 @@ public class OrdersController(ILogger<OrdersController> logger, IMediator mediat
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetOrders([FromServices] IOrderQueries orderQueries)
|
||||
{
|
||||
string? nameIdentifier = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
||||
|
||||
if (!int.TryParse(nameIdentifier, out int userId))
|
||||
{
|
||||
throw new ApplicationException("User id not found in claims.");
|
||||
}
|
||||
|
||||
IEnumerable<OrderSummary> orders = await orderQueries.GetOrdersFromUserAsync(userId);
|
||||
|
||||
return Ok(orders);
|
||||
}
|
||||
|
||||
[HttpGet("{id}")]
|
||||
public async Task<IActionResult> GetOrder(int id, [FromServices] IOrderQueries orderQueries)
|
||||
{
|
||||
OrderDetails order = await orderQueries.GetOrderAsync(id);
|
||||
|
||||
return Ok(order);
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
using HelloShop.OrderingService.Behaviors;
|
||||
using HelloShop.OrderingService.Constants;
|
||||
using HelloShop.OrderingService.Infrastructure;
|
||||
using HelloShop.OrderingService.Queries;
|
||||
using HelloShop.OrderingService.Services;
|
||||
using HelloShop.OrderingService.Workers;
|
||||
using HelloShop.ServiceDefaults.DistributedEvents.Abstractions;
|
||||
@ -48,6 +49,8 @@ namespace HelloShop.OrderingService.Extensions
|
||||
options.AddOpenBehavior(typeof(TransactionBehavior<,>));
|
||||
});
|
||||
|
||||
builder.Services.AddScoped<IOrderQueries, OrderQueries>();
|
||||
|
||||
builder.Services.AddModelMapper().AddModelValidator();
|
||||
|
||||
builder.Services.AddTransient<ISmsSender, MessageService>().AddTransient<IEmailSender, MessageService>();
|
||||
|
@ -34,4 +34,14 @@ Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1laWQiOiIxIiwi
|
||||
]
|
||||
}
|
||||
|
||||
###
|
||||
###
|
||||
|
||||
GET {{HelloShop.OrderingService_HostAddress}}/api/orders
|
||||
Content-Type: application/json
|
||||
Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1laWQiOiIxIiwidW5pcXVlX25hbWUiOiJhZG1pbiIsInJvbGVpZCI6IjEiLCJuYmYiOjE3MjA1NzY3NDYsImV4cCI6MTc0MjYwODc0NiwiaWF0IjoxNzIwNTc2NzQ2fQ.ju_D3zeGLKqJYVckbb8Y3yNkp40nOqRAJrdOsISs4d4
|
||||
|
||||
###
|
||||
|
||||
GET {{HelloShop.OrderingService_HostAddress}}/api/orders/1
|
||||
Content-Type: application/json
|
||||
Authorization : Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1laWQiOiIxIiwidW5pcXVlX25hbWUiOiJhZG1pbiIsInJvbGVpZCI6IjEiLCJuYmYiOjE3MjA1NzY3NDYsImV4cCI6MTc0MjYwODc0NiwiaWF0IjoxNzIwNTc2NzQ2fQ.ju_D3zeGLKqJYVckbb8Y3yNkp40nOqRAJrdOsISs4d4
|
||||
|
12
src/HelloShop.OrderingService/Queries/IOrderQueries.cs
Normal file
12
src/HelloShop.OrderingService/Queries/IOrderQueries.cs
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright (c) HelloShop Corporation. All rights reserved.
|
||||
// See the license file in the project root for more information.
|
||||
|
||||
namespace HelloShop.OrderingService.Queries
|
||||
{
|
||||
public interface IOrderQueries
|
||||
{
|
||||
Task<OrderDetails> GetOrderAsync(int id);
|
||||
|
||||
Task<IEnumerable<OrderSummary>> GetOrdersFromUserAsync(int userId);
|
||||
}
|
||||
}
|
28
src/HelloShop.OrderingService/Queries/OrderDetails.cs
Normal file
28
src/HelloShop.OrderingService/Queries/OrderDetails.cs
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright (c) HelloShop Corporation. All rights reserved.
|
||||
// See the license file in the project root for more information.
|
||||
|
||||
namespace HelloShop.OrderingService.Queries
|
||||
{
|
||||
public class OrderDetails
|
||||
{
|
||||
public int OrderId { get; init; }
|
||||
|
||||
public required string Status { get; init; }
|
||||
|
||||
public DateTimeOffset OrderDate { get; init; }
|
||||
|
||||
public required string Country { get; init; }
|
||||
|
||||
public required string State { get; init; }
|
||||
|
||||
public required string City { get; init; }
|
||||
|
||||
public required string Street { get; init; }
|
||||
|
||||
public required string ZipCode { get; init; }
|
||||
|
||||
public string? Description { get; init; }
|
||||
|
||||
public required List<OrderDetailsItem> OrderItems { get; set; }
|
||||
}
|
||||
}
|
18
src/HelloShop.OrderingService/Queries/OrderDetailsItem.cs
Normal file
18
src/HelloShop.OrderingService/Queries/OrderDetailsItem.cs
Normal file
@ -0,0 +1,18 @@
|
||||
// Copyright (c) HelloShop Corporation. All rights reserved.
|
||||
// See the license file in the project root for more information.
|
||||
|
||||
namespace HelloShop.OrderingService.Queries
|
||||
{
|
||||
public class OrderDetailsItem
|
||||
{
|
||||
public int ProductId { get; init; }
|
||||
|
||||
public required string ProductName { get; init; }
|
||||
|
||||
public int Units { get; init; }
|
||||
|
||||
public double UnitPrice { get; init; }
|
||||
|
||||
public required string PictureUrl { get; init; }
|
||||
}
|
||||
}
|
41
src/HelloShop.OrderingService/Queries/OrderQueries.cs
Normal file
41
src/HelloShop.OrderingService/Queries/OrderQueries.cs
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright (c) HelloShop Corporation. All rights reserved.
|
||||
// See the license file in the project root for more information.
|
||||
|
||||
using AutoMapper;
|
||||
using HelloShop.OrderingService.Constants;
|
||||
using HelloShop.OrderingService.Entities.Orders;
|
||||
using HelloShop.OrderingService.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace HelloShop.OrderingService.Queries
|
||||
{
|
||||
public class OrderQueries : IOrderQueries
|
||||
{
|
||||
private readonly OrderingServiceDbContext _dbContext;
|
||||
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public OrderQueries(OrderingServiceDbContext dbContext, IMapper mapper, IConfiguration configuration)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
// TODO:Provide the AddKeyedDbContext extension method on Services at https://github.com/dotnet/efcore/issues/34591
|
||||
dbContext.Database.SetConnectionString(configuration.GetConnectionString(DbConstants.SlaveConnectionStringName));
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<OrderDetails> GetOrderAsync(int id)
|
||||
{
|
||||
var order = await _dbContext.Set<Order>().AsNoTracking().Include(o => o.OrderItems).SingleOrDefaultAsync(o => o.Id == id);
|
||||
var orderDetails = _mapper.Map<OrderDetails>(order);
|
||||
|
||||
return orderDetails;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<OrderSummary>> GetOrdersFromUserAsync(int userId)
|
||||
{
|
||||
var orders = await _dbContext.Set<Order>().AsNoTracking().Where(o => o.BuyerId == userId).ToListAsync();
|
||||
var orderSummaries = _mapper.Map<IEnumerable<OrderSummary>>(orders);
|
||||
return orderSummaries;
|
||||
}
|
||||
}
|
||||
}
|
14
src/HelloShop.OrderingService/Queries/OrderSummary.cs
Normal file
14
src/HelloShop.OrderingService/Queries/OrderSummary.cs
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright (c) HelloShop Corporation. All rights reserved.
|
||||
// See the license file in the project root for more information.
|
||||
|
||||
namespace HelloShop.OrderingService.Queries
|
||||
{
|
||||
public class OrderSummary
|
||||
{
|
||||
public int OrderId { get; init; }
|
||||
|
||||
public required string Status { get; init; }
|
||||
|
||||
public DateTimeOffset OrderDate { get; init; }
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user