C# 使用MediatR编辑操作CQRS模式
我有一个.NETCore3.1MVC应用程序,我正在尝试使用CQRS模式。我是MediatR和CQRS模式的新手 我的命令/查询结构如下:C# 使用MediatR编辑操作CQRS模式,c#,asp.net-core,cqrs,mediatr,C#,Asp.net Core,Cqrs,Mediatr,我有一个.NETCore3.1MVC应用程序,我正在尝试使用CQRS模式。我是MediatR和CQRS模式的新手 我的命令/查询结构如下: 类别 命令 删除类别 高级类别 询问 GetCategoriesList 类别列表 类别 GetCategoriesListQuery GetCategoriesListQueryHandler 我想使用相同的视图来创建和更新操作,因为我的类别只有两个属性。(其中一个是身份证) My CategoryController.cs文件 [H
- 类别
- 命令
- 删除类别
- 高级类别
- 询问
- GetCategoriesList
- 类别列表
- 类别
- GetCategoriesListQuery
- GetCategoriesListQueryHandler
- GetCategoriesList
- 命令
[HttpGet]
public IActionResult Upsert(long? id) {
if (id == null) {
//Create new, working correctly.
return View();
}
//Update existing not working.
return View(new UpsertCategoryCommand() { Id = id });
}
[HttpPost]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesDefaultResponseType]
public async Task<IActionResult> Upsert(UpsertCategoryCommand command) {
if (ModelState.IsValid) {
await Mediator.Send(command);
return RedirectToAction(nameof(Index));
} else {
return View(command);
}
}
[HttpGet]
公共IActionResult Upsert(长?id){
if(id==null){
//创建新的,工作正常。
返回视图();
}
//更新现有的不工作。
返回视图(新的UpsertCategoryCommand(){Id=Id});
}
[HttpPost]
[产品响应类型(StatusCodes.Status200OK)]
[ProductsDefaultResponseType]
公共异步任务Upsert(UpsertCategoryCommand命令){
if(ModelState.IsValid){
等待调解人。发送(命令);
返回重定向到操作(名称(索引));
}否则{
返回视图(命令);
}
}
我的类别/索引视图在此处调用upsert方法
<tbody>
@foreach (var item in Model.Categories) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.ActionLink("Edit", "Upsert", new { Id = item.Id }) |
@Html.ActionLink("Delete", "Delete", new { Id = item.Id})
</td>
</tr>
}
</tbody>
@foreach(Model.Categories中的var项){
@DisplayFor(modelItem=>item.Name)
@ActionLink(“编辑”,“插入”,新建{Id=item.Id})|
@ActionLink(“删除”,“删除”,新的{Id=item.Id})
}
我只想将Id信息发送给控制器,然后发送到UpsertCategoryCommand的映射方式/位置
所有其他型号:
//UpsertCategoryCommand.cs
namespace ...Categorys.Commands.UpsertCategory {
public class UpsertCategoryCommand : IRequest<long> {
public long? Id { get; set; }
public string Name { get; set; }
public class UpsertCategoryCommandHandler : IRequestHandler<UpsertCategoryCommand, long> {
private readonly ITestDbContext _context;
public UpsertCategoryCommandHandler(ITestDbContext context) {
_context = context;
}
public async Task<long> Handle(UpsertCategoryCommand request, CancellationToken cancellationToken) {
Category entity;
if (request.Id.HasValue) {
entity = await _context.Categories.FindAsync(request.Id.Value);
} else {
entity = new Category();
_context.Categories.Add(entity);
}
entity.Name = request.Name;
await _context.SaveChangesAsync(cancellationToken);
return entity.Id;
}
}
}
}
//UpsertCategoryCommandValidator.cs
namespace ...Categories.Commands.UpsertCategory {
public class UpsertCategoryCommandValidator : AbstractValidator<UpsertCategoryCommand> {
private readonly ITestDbContext _context;
public UpsertCategoryCommandValidator(ITestDbContext context) {
_context = context;
RuleFor(x => x.Name).MaximumLength(100).NotEmpty();
RuleFor(x => x.Name)
.Must(UniqueName)
.WithMessage("Category name must be unique."); ;
}
private bool UniqueName(UpsertCategoryCommand category, string name) {
var dbCategory = _context.Categories
.Where(x => x.Name.ToLower() == name.ToLower())
.SingleOrDefault();
if (dbCategory == null)
return true;
return dbCategory.Id == category.Id;
}
}
}
//CategoryDto.cs
namespace ...Categories.Queries.GetCategoryList {
public class CategoryDto : IMapFrom<Category> {
public long Id { get; set; }
public string Name { get; set; }
public void Mapping(Profile profile) {
profile.CreateMap<Category, CategoryDto>();
}
}
}
//UpsertCategoryCommand.cs
命名空间…Categorys.Commands.UpsertCategory{
公共类UpsertCategoryCommand:IRequest{
公共long?Id{get;set;}
公共字符串名称{get;set;}
公共类UpsertCategoryCommandHandler:IRequestHandler{
私有只读ITestDbContext\u context;
public UpsertCategoryCommandHandler(ITestDbContext上下文){
_上下文=上下文;
}
公共异步任务句柄(UpsertCategoryCommand请求、CancellationToken CancellationToken){
类别实体;
if(request.Id.HasValue){
entity=wait_context.Categories.FindAsync(request.Id.Value);
}否则{
实体=新类别();
_context.Categories.Add(实体);
}
entity.Name=request.Name;
wait_context.saveChangesSync(cancellationToken);
返回实体Id;
}
}
}
}
//UpsertCategoryCommandValidator.cs
命名空间…Categories.Commands.UpsertCategory{
公共类UpsertCategoryCommandValidator:AbstractValidator{
私有只读ITestDbContext\u context;
公共UpsertCategoryCommandValidator(ITestDbContext上下文){
_上下文=上下文;
RuleFor(x=>x.Name).MaximumLength(100).NotEmpty();
RuleFor(x=>x.Name)
.Must(唯一名称)
.WithMessage(“类别名称必须唯一”);
}
private bool UniqueName(UpsertCategoryCommand类别,字符串名称){
var dbCategory=\u context.Categories
.Where(x=>x.Name.ToLower()==Name.ToLower())
.SingleOrDefault();
if(dbCategory==null)
返回true;
返回dbCategory.Id==category.Id;
}
}
}
//CategoryDto.cs
命名空间…Categories.querys.GetCategoryList{
公共类类别:IMapFrom{
公共长Id{get;set;}
公共字符串名称{get;set;}
公共空白映射(配置文件){
CreateMap();
}
}
}
创建和编辑同一页面以及映射的最佳实践是什么?我可以在命令中使用CategoryTo吗?为命令和查询定义任何常见的Dto,这是否好?我将为CreateCography和UpdateCategory创建单独的命令,以便更清楚地了解用户的意图。我还认为这些命令的响应应该是不同的类型,并尽量避免在命令之间重用类 我还将只在每个命令中包含真正必要的字段,而不尝试在各种命令中重用CategoryDto
因此您将拥有CreateCategoryReporte和UpdateCategoryResponse类型。我想吉米在最近的一次谈话中也讨论过这个问题。我也有同样的问题。我对常见的DTO感到困惑。在我的例子中,类别只有两个属性。如果我创建两个不同的命令,就会有许多重复的代码。若我并没有,我会解决重复代码的问题,但那个是时候,我有一个额外的映射和不必要的若控制命令。所以,我想我会选择重复的代码或者额外的控件。实际上,在很多情况下,重复的代码通常是一件好事。。。。它消除了许多耦合和依赖性。。。每个命令和处理程序应尽可能独立于其他命令/处理程序。是否看到此视频