简体   繁体   English

使用 MediatR 编辑动作 CQRS 模式

[英]Edit action CQRS pattern using MediatR

I have a.Net Core 3.1 MVC application and I am trying to use CQRS pattern.我有一个 .Net Core 3.1 MVC 应用程序,我正在尝试使用 CQRS 模式。 I am new in MediatR and CQRS pattern.我是 MediatR 和 CQRS 模式的新手。

My commmand/query structure like that:我的命令/查询结构是这样的:

在此处输入图像描述

  • Categories类别
    • Commands命令
      • DeleteCategory删除类别
      • UpsertCategory更新插入类别
    • Queries查询
      • GetCategoriesList获取类别列表
        • CategoryListVm类别列表虚拟机
        • CategoryDto类别Dto
        • GetCategoriesListQuery获取类别列表查询
        • GetCategoriesListQueryHandler GetCategoriesListQueryHandler

I want to use same view to create and update operation because my category has only two properties.我想使用相同的视图来创建和更新操作,因为我的类别只有两个属性。 (One of them is Id) (其中一个是Id)

My CategoryController.cs file我的 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);
        }
    }

My Category/Index view call upsert method in here.我的类别/索引视图在这里调用 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>

I want to send only Id information to controller and then how/where I map/get to UpsertCategoryCommand.我只想将 Id 信息发送到 controller,然后我如何/在哪里映射/到达 UpsertCategoryCommand。

All other models:所有其他型号:

    //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>();
            }
        }
    }

What is the best practies to doing same page for create and edit and also mapping?为创建和编辑以及映射执行同一页面的最佳实践是什么? Could I use CategoryDto in my commands?我可以在我的命令中使用 CategoryDto 吗? Define to any common Dto for commands and queries, is good?为命令和查询定义任何常见的 Dto,好吗?

I would create separate commands for CreateCategory and UpdateCategory, to be more clear about the intent of the user.我将为 CreateCategory 和 UpdateCategory 创建单独的命令,以便更清楚地了解用户的意图。 I also think the response from these commands should be separate types and try to avoid reusing classes between the commands.我还认为这些命令的响应应该是单独的类型,并尽量避免在命令之间重用类。

I would also only include the really necessary fields in each command, and not try to reuse the CategoryDto in the various commands.我也只会在每个命令中包含真正必要的字段,而不是尝试在各种命令中重用 CategoryDto。

So you would have a CreateCategoryReponse and UpdateCategoryResponse type.所以你会有一个 CreateCategoryReponse 和 UpdateCategoryResponse 类型。 I also think Jimmy discussed this in one of his more recent talks.我也认为吉米在他最近的一次谈话中讨论了这个问题。

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

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