繁体   English   中英

使用 MediatR 编辑动作 CQRS 模式

[英]Edit action CQRS pattern using MediatR

我有一个 .Net Core 3.1 MVC 应用程序,我正在尝试使用 CQRS 模式。 我是 MediatR 和 CQRS 模式的新手。

我的命令/查询结构是这样的:

在此处输入图像描述

  • 类别
    • 命令
      • 删除类别
      • 更新插入类别
    • 查询
      • 获取类别列表
        • 类别列表虚拟机
        • 类别Dto
        • 获取类别列表查询
        • GetCategoriesListQueryHandler

我想使用相同的视图来创建和更新操作,因为我的类别只有两个属性。 (其中一个是Id)

我的 CategoryController.cs 文件

[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);
        }
    }

我的类别/索引视图在这里调用 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>

我只想将 Id 信息发送到 controller,然后我如何/在哪里映射/到达 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>();
            }
        }
    }

为创建和编辑以及映射执行同一页面的最佳实践是什么? 我可以在我的命令中使用 CategoryDto 吗? 为命令和查询定义任何常见的 Dto,好吗?

我将为 CreateCategory 和 UpdateCategory 创建单独的命令,以便更清楚地了解用户的意图。 我还认为这些命令的响应应该是单独的类型,并尽量避免在命令之间重用类。

我也只会在每个命令中包含真正必要的字段,而不是尝试在各种命令中重用 CategoryDto。

所以你会有一个 CreateCategoryReponse 和 UpdateCategoryResponse 类型。 我也认为吉米在他最近的一次谈话中讨论了这个问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM