編輯產品類似于添加新產品,現在讓我們看看如何編輯產品:
## 定義應用接口
讓我們從為`IProductAppService`接口定義兩個新方法:
```
Task<ProductDto> GetAsync(Guid id);
Task UpdateAsync(Guid id, CreateUpdateProductDto input);
```
第一種方法用于通過ID獲取產品。我們在`UpdateAsync`方法中重用之前定義的`CreateUpdateProductDto`。
## 實現應用接口
實現這些新方法非常簡單。將以下方法添加到`ProductAppService`類中:
```
public async Task<ProductDto> GetAsync(Guid id)
{
????return ObjectMapper.Map<Product, ProductDto>(
????????await _productRepository.GetAsync(id)
????);
}
public async Task UpdateAsync(Guid id, CreateUpdateProductDto input)
{
????var product = await _productRepository.GetAsync(id);
????ObjectMapper.Map(input, product);
}
```
`GetAsync`方法用于從數據庫中獲取產品,并將其映射到`ProductDto`對象后進行返回。`UpdateAsync`方法獲取到一個產品后,將給定的DTO輸入映射到產品。通過這種方式,我們用新值覆蓋產品。
對于這個例子,我們不需要調用`_productRepository.UpdateAsync`,因為 EF Core有一個變更跟蹤系統。ABP 的**工作單元**如果沒有拋出異常,則在請求結束時會自動保存更改。我們將在\[*第 6 章*\] \*使用數據訪問基礎架構”\*中介紹工作單元系統。
應用層已完成。接下來,我們將創建一個產品編輯 UI。
## 用戶界面
創建一個`EditProductModal.cshtml`Razor 頁面(*ProductManagement.Web項目的* *Pages/Products*文件夾下)。打開`EditProductModal.cshtml.cs`,代碼更改如下:
```
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using ProductManagement.Products;
namespace ProductManagement.Web.Pages.Products
{
????public class EditProductModalModel :?ProductManagementPageModel
????{
????????[HiddenInput]
????????[BindProperty(SupportsGet = true)]
????????public Guid Id { get; set; }
????????[BindProperty]
????????public CreateEditProductViewModel Product { get; set; }
????????public SelectListItem[] Categories { get; set; }
????????private readonly IProductAppService _productAppService;
????????public EditProductModalModel(IProductAppService productAppService)
????????{
????????????_productAppService = productAppService;
????????}
????????public async Task OnGetAsync()
????????{
????????????// TODO
????????}
????????public async Task<IActionResult> OnPostAsync()
????????{
????????????// TODO
????????}
????}
}
```
表單中`Id`字段將被隱藏。
它還應該支持 HTTP GET 請求,因為 GET 請求會打開此模型,并且我們需要產品 ID 來編輯表單。
`Product`和`Categories`屬性類似于創建產品。
我們還將`IProductAppService`接口注入到構造函數。
我們實現`OnGetAsync`方法,如下代碼塊所示:
```
public async Task OnGetAsync()
{
????var productDto = await _productAppService.GetAsync(Id);
????Product = ObjectMapper.Map<ProductDto,?CreateEditProductViewModel>(productDto);
????
????var categoryLookup = await?_productAppService.GetCategoriesAsync();
????Categories = categoryLookup.Items
????????.Select(x => new SelectListItem(x.Name, x.Id.ToString()))
????????.ToArray();
}
```
首先,我們要先獲取一個產品 ( `ProductDto`),再將其轉換為`CreateEditProductViewModel`,使用它在 UI 上來創建編輯表單。然后,我們在表單上選擇產品類別。
因為這里映射了`ProductDto`到`CreateEditProductViewModel`,所以我們需要在`ProductManagementWebAutoMapperProfile`類中定義配置映射([*ProductManagement.Web*](http://ProductManagement.Web)項目中),這和我們之前操作是一樣的:
```
CreateMap<ProductDto, CreateEditProductViewModel>();
```
我們再看下`OnPostAsync()`方法:
```
public async Task<IActionResult> OnPostAsync()
{
????await _productAppService.UpdateAsync(Id,
????????ObjectMapper.Map<CreateEditProductViewModel,?????????????????????????????CreateUpdateProductDto>(Product)
????);
????return NoContent();
}
```
`OnPostAsync`方法很簡單,把`CreateEditProductViewModel`轉換為`CreateUpdateProductDto`。
接著,我們切換到`EditProductModal.cshtml`,內容更改如下:
```
@page
@using Microsoft.AspNetCore.Mvc.Localization
@using ProductManagement.Localization
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
@model ProductManagement.Web.Pages.Products.EditProductModalModel
@inject IHtmlLocalizer<ProductManagementResource> L
@{
????Layout = null;
}
<abp-dynamic-form abp-model="Product" asp-page="/Products/EditProductModal">
????<abp-modal>
????????<abp-modal-header title="@Model.Product.Name"></abp-modal-header>
????????<abp-modal-body>
????????????<abp-input asp-for="Id" />
????????????<abp-form-content/>
????????</abp-modal-body>
????????<abp-modal-footer buttons="@(AbpModalButtons.Cancel|AbpModalButtons.Save)"></abp-modal-footer>
????</abp-modal>
</abp-dynamic-form>
```
頁面與`CreateProductModal.cshtml`非常相似。我剛剛將`Id`字段作為隱藏字段添加到表單,用來存儲`Id`編輯的產品的屬性。
最后,我們可以添加一個**編輯**按鈕以從產品列表中打開編輯模態窗口。打開`Index.cshtml.js`文件,并在`dataTable`代碼的頭部添加一個`ModalManager`對象:
```
var editModal = new abp.ModalManager(abp.appPath + 'Products/EditProductModal');
```
然后,在`dataTable`內部的`columnDefs`數組中定義一個列(第一項):
```
{
????title: l('Actions'),
????rowAction: {
????????items:
????????????[
????????????????{
????????????????????text: l('Edit'),
????????????????????action: function (data) {
????????????????????????editModal.open({ id: data.record.id });
????????????????????}
????????????????}
????????????]
????}
},
```
此代碼向數據表添加了一個新的**Actions**列,并添加了一個**Edit**操作按鈕,單擊即可打開編輯窗口。`rowAction`是 ABP Framework 提供的一個特殊選項。它用于在表中的一行添加一個或多個操作按鈕。
最后,在`dataTable`初始化代碼后添加如下:
```
editModal.onResult(function () {
????dataTable.ajax.reload();
});
```
在保存產品編輯對話框后刷新數據表,確保我們可以看到表上的最新數據。最終的 UI 類似于下圖:

我們現在可以查看、創建和編輯產品了。最后一部分將實現刪除產品。
- 前言
- 第一部分
- 第1章 現代軟件開發和 ABP 框架
- 企業級 Web 開發的挑戰
- ABP框架的能力清單
- 第2章 ABP框架入門
- 安裝 ABP CLI
- 創建新解決方案
- 運行解決方案
- 探索預構建模塊
- 第3章 逐步開發開發ABP應用
- 創建解決方案
- 定義領域對象
- EFCore和數據庫映射
- 定義應用服務
- 測試產品
- 產品列表
- 創建產品
- 編輯產品
- 刪除產品
- 第4章 探索 EventHub解決方案
- 應用介紹
- 架構探索
- 方案運行
- 第二部分
- 第5章 探索ABP基礎架構
- 了解模塊化
- 使用依賴注入系統
- 配置應用程序
- 實現選項模式
- 日志系統
- 第6章 數據訪問基礎架構
- 定義實體
- 定義倉儲庫
- EF Core集成
- 了解 UoW
- 第7章 探索橫切關注點
- 認證授權
- 用戶驗證
- 異常處理
- 第8章 體驗 ABP 的功能和服務
- 獲取當前用戶
- 使用數據過濾
- 控制審計日志
- 緩存數據
- 本地化用戶界面
- 第三部分
- 第9章 理解領域驅動設計
- 介紹 DDD
- 構建基于 DDD 的 解決方案
- 處理多個應用程序
- 了解執行流程
- DDD的通用原則
- 第10章 領域層 Domain
- 領域事件案例分析
- 聚合和實體的設計原則和實踐
- 實現領域服務
- 落地存儲庫
- 構建規約(Specification)
- 領域事件
- 第11章 應用層 Application
- 落地應用服務
- 設計 DTO
- 理解各層的職責
- 第四部分
- 第12章 MVC/Razor 頁面
- 主題系統
- 綁定和壓縮
- 導航菜單
- Bootstrap標簽助手
- 創建表單并驗證
- 使用模態窗口
- 使用JS API
- 調用HTTP API
- 第13章 Blazor WebAssembly UI
- 什么是Blazor
- ABP Blazor UI
- 驗證用戶身份
- 理解主題系統
- 使用菜單
- 使用基本服務
- 使用UI服務
- 消費HTTP API
- 使用全局腳本和樣式
- 第14章 HTTP API 和實時服務
- 構建HTTP API
- 使用HTTP API
- 使用SignalR
- 第五部分
- 第15章 落地模塊化
- 理解模塊化
- 構建支付模塊
- 安裝模塊
- 第16章 實現多租戶
- 理解多租戶
- 多租戶基礎設施
- 使用功能系統
- 何時使用多租戶
- 第17章 構建自動化測試
- 了解ABP測試基礎設施
- 構建單元測試
- 構建集成測試