ABP框架+Mysql(三)

创建,更新和删除图书

创建新书籍

创建 modal form

在 Acme.BookStore.Web 项目的 Pages/Books 目录下新建一个 CreateModal.cshtml Razor页面:

CreateModal.cshtml.cs

打开 CreateModal.cshtml.cs 代码文件(CreateModalModel 类),替换成以下代码:

using System.Threading.Tasks;
using Acme.BookStore.Books;
using Microsoft.AspNetCore.Mvc;namespace Acme.BookStore.Web.Pages.Books
{public class CreateModalModel : BookStorePageModel{[BindProperty]public CreateUpdateBookDto Book { get; set; }private readonly IBookAppService _bookAppService;public CreateModalModel(IBookAppService bookAppService){_bookAppService = bookAppService;}public void OnGet(){Book = new CreateUpdateBookDto();}public async Task<IActionResult> OnPostAsync(){await _bookAppService.CreateAsync(Book);return NoContent();}}
}
  • 该类派生于 BookStorePageModel 而非默认的 PageModelBookStorePageModel 间接继承了 PageModel 并且添加了一些可以被你的page model类使用的通用属性和方法.
  • Book 属性上的 [BindProperty] 特性将post请求提交上来的数据绑定到该属性上.
  • 该类通过构造函数注入了 IBookAppService 应用服务,并且在 OnPostAsync 处理程序中调用了服务的 CreateAsync 方法.
  • 它在 OnGet 方法中创建一个新的 CreateUpdateBookDto 对象。 ASP.NET Core不需要像这样创建一个新实例就可以正常工作. 但是它不会为你创建实例,并且如果你的类在类构造函数中赋值一些默认值或执行一些代码,它们将无法工作. 对于这种情况,我们为某些 CreateUpdateBookDto 属性设置了默认值.
CreateModal.cshtml

打开 CreateModal.cshtml 文件并粘贴如下代码:

@page
@using Acme.BookStore.Localization
@using Acme.BookStore.Web.Pages.Books
@using Microsoft.Extensions.Localization
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
@model CreateModalModel
@inject IStringLocalizer<BookStoreResource> L
@{Layout = null;
}
<abp-dynamic-form abp-model="Book" asp-page="/Books/CreateModal"><abp-modal><abp-modal-header title="@L["NewBook"].Value"></abp-modal-header><abp-modal-body><abp-form-content /></abp-modal-body><abp-modal-footer buttons="@(AbpModalButtons.Cancel|AbpModalButtons.Save)"></abp-modal-footer></abp-modal>
</abp-dynamic-form>
  • 这个 modal 使用 abp-dynamic-form tag Helper 根据 CreateUpdateBookDto 类自动构建了表单.
  • abp-model 指定了 Book 属性为模型对象.
  • abp-form-content tag helper 作为表单控件渲染位置的占位符 (这是可选的,只有你在 abp-dynamic-form 中像本示例这样添加了其他内容才需要).

添加 "New book" 按钮

打开 Pages/Books/Index.cshtml 并按如下代码修改 abp-card-header :

<abp-card-header><abp-row><abp-column size-md="_6"><abp-card-title>@L["Books"]</abp-card-title></abp-column><abp-column size-md="_6" class="text-end"><abp-button id="NewBookButton"text="@L["NewBook"].Value"icon="plus"button-type="Primary"/></abp-column></abp-row>
</abp-card-header>

Index.cshtml 的内容最终如下所示:

@page
@using Acme.BookStore.Localization
@using Acme.BookStore.Web.Pages.Books
@using Microsoft.Extensions.Localization
@model IndexModel
@inject IStringLocalizer<BookStoreResource> L
@section scripts
{<abp-script src="/Pages/Books/Index.js"/>
}<abp-card><abp-card-header><abp-row><abp-column size-md="_6"><abp-card-title>@L["Books"]</abp-card-title></abp-column><abp-column size-md="_6" class="text-end"><abp-button id="NewBookButton"text="@L["NewBook"].Value"icon="plus"button-type="Primary"/></abp-column></abp-row></abp-card-header><abp-card-body><abp-table striped-rows="true" id="BooksTable"></abp-table></abp-card-body>
</abp-card>

 在图书页面加入了 一个添加按钮

打开 Pages/Book/Index.js 在 datatable 配置代码后面添加如下代码:

var createModal = new abp.ModalManager(abp.appPath + 'Books/CreateModal');createModal.onResult(function () {dataTable.ajax.reload();
});$('#NewBookButton').click(function (e) {e.preventDefault();createModal.open();
});
  • abp.ModalManager 是一个在客户端管理modal的辅助类.它内部使用了Twitter Bootstrap的标准modal组件,但通过简化的API抽象了许多细节.
  • createModal.onResult(...) 用于在创建书籍后刷新数据表格.
  • createModal.open(); 用于打开modal创建新书籍.

Index.js 的内容最终如下所示:

$(function () {var l = abp.localization.getResource('BookStore');var dataTable = $('#BooksTable').DataTable(abp.libs.datatables.normalizeConfiguration({serverSide: true,paging: true,order: [[1, "asc"]],searching: false,scrollX: true,ajax: abp.libs.datatables.createAjax(acme.bookStore.books.book.getList),columnDefs: [{title: l('Name'),data: "name"},{title: l('Type'),data: "type",render: function (data) {return l('Enum:BookType:' + data);}},{title: l('PublishDate'),data: "publishDate",render: function (data) {return luxon.DateTime.fromISO(data, {locale: abp.localization.currentCulture.name}).toLocaleString();}},{title: l('Price'),data: "price"},{title: l('CreationTime'), data: "creationTime",render: function (data) {return luxon.DateTime.fromISO(data, {locale: abp.localization.currentCulture.name}).toLocaleString(luxon.DateTime.DATETIME_SHORT);}}]}));var createModal = new abp.ModalManager(abp.appPath + 'Books/CreateModal');createModal.onResult(function () {dataTable.ajax.reload();});$('#NewBookButton').click(function (e) {e.preventDefault();createModal.open();});
});

现在,你可以 运行程序 通过新的 modal form 来创建书籍了.

更新书籍

在 Acme.BookStore.Web 项目的 Pages/Books 目录下新建一个名叫 EditModal.cshtml 的Razor页面:

EditModal.cshtml.cs

打开 EditModal.cshtml.cs 文件(EditModalModel类) 并替换成以下代码:

using System;
using System.Threading.Tasks;
using Acme.BookStore.Books;
using Microsoft.AspNetCore.Mvc;namespace Acme.BookStore.Web.Pages.Books
{public class EditModalModel : BookStorePageModel{[HiddenInput][BindProperty(SupportsGet = true)]public Guid Id { get; set; }[BindProperty]public CreateUpdateBookDto Book { get; set; }private readonly IBookAppService _bookAppService;public EditModalModel(IBookAppService bookAppService){_bookAppService = bookAppService;}public async Task OnGetAsync(){var bookDto = await _bookAppService.GetAsync(Id);Book = ObjectMapper.Map<BookDto, CreateUpdateBookDto>(bookDto);}public async Task<IActionResult> OnPostAsync(){await _bookAppService.UpdateAsync(Id, Book);return NoContent();}}
}
  • [HiddenInput] 和 [BindProperty] 是标准的 ASP.NET Core MVC 特性.这里启用 SupportsGet 从Http请求的查询字符串参数中获取Id的值.
  • 在 OnGetAsync 方法中, 我们从 BookAppService 获得 BookDto ,并将它映射成DTO对象 CreateUpdateBookDto.
  • OnPostAsync 方法直接使用 BookAppService.UpdateAsync 来更新实体.

BookDto 到 CreateUpdateBookDto 对象映射

为了执行 BookDto 到 CreateUpdateBookDto 对象映射,请打开 Acme.BookStore.Web 项目中的 BookStoreWebAutoMapperProfile.cs 并更改它,如下所示:

using Acme.BookStore.Books;
using AutoMapper;namespace Acme.BookStore.Web;public class BookStoreWebAutoMapperProfile : Profile
{public BookStoreWebAutoMapperProfile(){//Define your AutoMapper configuration here for the Web project.CreateMap<BookDto, CreateUpdateBookDto>();}
}

我们添加了 CreateMap<BookDto, CreateUpdateBookDto>(); 作为映射定义.

请注意,我们在Web层中进行映射定义是一种最佳实践,因为仅在该层中需要它.

EditModal.cshtml

将 EditModal.cshtml 页面内容替换成如下代码:

@page
@using Acme.BookStore.Localization
@using Acme.BookStore.Web.Pages.Books
@using Microsoft.Extensions.Localization
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
@model EditModalModel
@inject IStringLocalizer<BookStoreResource> L
@{Layout = null;
}
<abp-dynamic-form abp-model="Book" asp-page="/Books/EditModal"><abp-modal><abp-modal-header title="@L["Update"].Value"></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>

这个页面内容和 CreateModal.cshtml 非常相似,除了以下几点:

  • 它包含id属性的abp-input, 用于存储被编辑书籍的 id (它是隐藏的Input)
  • 此页面指定的post地址是Books/EditModal.

为表格添加 "操作(Actions)" 下拉菜单

我们将为表格每行添加下拉按钮 ("Actions"):

打开 Pages/Books/Index.js 页面,并按下方所示修改表格部分的代码:

$(function () {var l = abp.localization.getResource('BookStore');var createModal = new abp.ModalManager(abp.appPath + 'Books/CreateModal');var editModal = new abp.ModalManager(abp.appPath + 'Books/EditModal');var dataTable = $('#BooksTable').DataTable(abp.libs.datatables.normalizeConfiguration({serverSide: true,paging: true,order: [[1, "asc"]],searching: false,scrollX: true,ajax: abp.libs.datatables.createAjax(acme.bookStore.books.book.getList),columnDefs: [{title: l('Actions'),rowAction: {items:[{text: l('Edit'),action: function (data) {editModal.open({ id: data.record.id });}}]}},{title: l('Name'),data: "name"},{title: l('Type'),data: "type",render: function (data) {return l('Enum:BookType:' + data);}},{title: l('PublishDate'),data: "publishDate",render: function (data) {return luxon.DateTime.fromISO(data, {locale: abp.localization.currentCulture.name}).toLocaleString();}},{title: l('Price'),data: "price"},{title: l('CreationTime'), data: "creationTime",render: function (data) {return luxon.DateTime.fromISO(data, {locale: abp.localization.currentCulture.name}).toLocaleString(luxon.DateTime.DATETIME_SHORT);}}]}));createModal.onResult(function () {dataTable.ajax.reload();});editModal.onResult(function () {dataTable.ajax.reload();});$('#NewBookButton').click(function (e) {e.preventDefault();createModal.open();});
});
  • 增加了一个新的 ModalManager 名为 editModal 打开编辑模态框.
  • 在 columnDefs 部分的开头添加了一个新列,用于"Actions"下拉按钮.
  • "Edit" 动作简单地调用 editModal.open() 打开编辑模态框.
  • editModal.onResult(...) 当你关闭编程模态框时进行回调刷新数据表格.

效果图如上图所示

删除书籍

打开 Pages/book/index.js 文件,在 rowAction items 下新增一项:

{text: l('Delete'),confirmMessage: function (data) {return l('BookDeletionConfirmationMessage', data.record.name);},action: function (data) {acme.bookStore.books.book.delete(data.record.id).then(function() {abp.notify.info(l('SuccessfullyDeleted'));dataTable.ajax.reload();});}
}
  • confirmMessage 执行 action 前向用户进行确认.
  • acme.bookStore.books.book.delete(...) 执行一个AJAX请求删除一个book.
  • abp.notify.info 执行删除操作后显示一个通知信息.

由于我们使用了两个新的本地化文本(BookDeletionConfirmationMessageSuccesslyDeleted),因此你需要将它们添加到本地化文件(Acme.BookStore.Domain.Shared项目的Localization/BookStore文件夹下的en.json):

"BookDeletionConfirmationMessage": "Are you sure to delete the book '{0}'?",
"SuccessfullyDeleted": "Successfully deleted!"

Index.js 的内容最终如下所示:

$(function () {var l = abp.localization.getResource('BookStore');var createModal = new abp.ModalManager(abp.appPath + 'Books/CreateModal');var editModal = new abp.ModalManager(abp.appPath + 'Books/EditModal');var dataTable = $('#BooksTable').DataTable(abp.libs.datatables.normalizeConfiguration({serverSide: true,paging: true,order: [[1, "asc"]],searching: false,scrollX: true,ajax: abp.libs.datatables.createAjax(acme.bookStore.books.book.getList),columnDefs: [{title: l('Actions'),rowAction: {items:[{text: l('Edit'),action: function (data) {editModal.open({ id: data.record.id });}},{text: l('Delete'),confirmMessage: function (data) {return l('BookDeletionConfirmationMessage',data.record.name);},action: function (data) {acme.bookStore.books.book.delete(data.record.id).then(function() {abp.notify.info(l('SuccessfullyDeleted'));dataTable.ajax.reload();});}}]}},{title: l('Name'),data: "name"},{title: l('Type'),data: "type",render: function (data) {return l('Enum:BookType:' + data);}},{title: l('PublishDate'),data: "publishDate",render: function (data) {return luxon.DateTime.fromISO(data, {locale: abp.localization.currentCulture.name}).toLocaleString();}},{title: l('Price'),data: "price"},{title: l('CreationTime'), data: "creationTime",render: function (data) {return luxon.DateTime.fromISO(data, {locale: abp.localization.currentCulture.name}).toLocaleString(luxon.DateTime.DATETIME_SHORT);}}]}));createModal.onResult(function () {dataTable.ajax.reload();});editModal.onResult(function () {dataTable.ajax.reload();});$('#NewBookButton').click(function (e) {e.preventDefault();createModal.open();});
});

你可以运行程序并尝试删除一本书.

如下图所示

到这里一个基本的CURD 就完成了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/20423.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用多种云进行OSS存储,详细教程

文章目录 这边文章是交大家进行多种云的存储,市场上主流的云存储,腾讯云,华为云,由于阿里云腾讯云 这边文章是交大家进行多种云的存储,市场上主流的云存储,腾讯云,华为云,由于 阿里云 阿里云本人以及出了详细的教程,这里就不讲解了,可以直接查看链接 阿里云实现思路: link 腾…

Html大前端与前端的区别:深度解析与实用指南

Html大前端与前端的区别&#xff1a;深度解析与实用指南 在谈论Html大前端与前端之间的区别时&#xff0c;我们首先需要理解这两者各自的定义和涵盖的范围。在软件开发的广阔领域中&#xff0c;前端与Html大前端各自扮演着不同的角色&#xff0c;并且随着技术的不断演进&#…

C/C++|回调函数的正确打开方式

最近在学习muduo库&#xff0c;其中的回调给我弄得晕头转向&#xff0c;后来才发现主要是回调函数的使用逻辑还没摸清楚&#xff0c;所以这里用一个简单的案例&#xff0c;来探究他们都是如何使用回调函数的。 一般回调函数都是用在类中&#xff1a; 我们将创建一个 EventHan…

【贪心算法题目练习】

1. 分发饼干 这道题目和我们之前讲到的田忌赛马的问题很相似&#xff0c;只不过这这里不需要劣等马去抵消掉优等马&#xff0c;直接上贪心策略&#xff1a; 先将两个数组排序。针对胃口较小的孩子&#xff0c;从小到大挑选饼干: i. 如果当前饼干能满足&#xff0c;直接喂(最小…

Windows安装Linux子系统WSL

Windows安装Linux子系统WSL 一、相比直接安装虚拟机优缺点:1、优点:2、缺点:二、开启WSL服务1、开启开发人员模式2、点开你电脑的设置然后点击应用3、安装过程4.启动5.那么共享文件在哪里呢?注意三、集成VScode开发环境1、新建终端2、选择WSL一、相比直接安装虚拟机优缺点:…

Flutter开发效率提升1000%,Flutter Quick教程之对组件进行拖拽与接收

1&#xff0c;首先&#xff0c;所有可以选择的组件&#xff0c;都在左边的组件面板里。从里面点击任何一个&#xff0c;按住左键&#xff0c;向右边的手机面板上进行拖拽即可。 2&#xff0c;拖拽后&#xff0c;我们要选择一个接收组件。什么时候可以接收组件&#xff0c;就是当…

Go 内存分配机制

是什么&#xff1f; Go语言内置运行的runtime&#xff0c;抛弃传统的内存分配方式&#xff0c;比如内存池&#xff0c;预分配等&#xff0c;这样不会每次内存分配都给系统调用。 为什么&#xff1f; golang的内存分配机制将程序员从手动管理内存的繁琐任务脱离出来。 怎么用…

反转字符串中的单词-力扣

此题将问题分为三步进行解决&#xff1a; 第一步&#xff0c;删除字符串中多余的空格&#xff0c;removeSpaces函数中删除所有的空格&#xff0c;并手动在每个单词后添加一个空格&#xff0c;最后重构字符串s第二步&#xff0c;将整个字符串反转第三步&#xff0c;对反转后的字…

代码随想录训练营Day57(单调栈解决最近大于或小于关系):Leetcode739、496、面试经典百题:Leetcode80、274

Leetcode739&#xff1a; 问题描述&#xff1a; 给定一个整数数组 temperatures &#xff0c;表示每天的温度&#xff0c;返回一个数组 answer &#xff0c;其中 answer[i] 是指对于第 i 天&#xff0c;下一个更高温度出现在几天后。如果气温在这之后都不会升高&#xff0c;请…

龙叔Linux:别名(alias)

在Linux中&#xff0c;别名&#xff08;alias&#xff09;是一个命令的简短形式&#xff0c;通常用于简化或替换更长的命令序列。你可以使用alias命令来创建、查看和删除别名&#xff0c;定制自己专属的命令。一、创建别名 1.1、临时创建 你可以使用alias命令在命令行中直接定…

B-TREE教程(个人总结版)

背景 在计算机科学中&#xff0c;数据存储和检索的效率是一个重要的研究课题。B-树&#xff08;B-Tree&#xff09;作为一种自平衡树结构&#xff0c;特别适合于在磁盘存储中处理大规模数据。它通过保持树的高度平衡&#xff0c;使得搜索、插入和删除操作的时间复杂度保持在对…

Spring (30)如何在Spring应用中启用Spring Security

在Spring应用中启用Spring Security涉及几个关键步骤&#xff0c;包括引入Spring Security依赖、创建安全配置类以及配置应用的安全细节。下面&#xff0c;我们将深入探讨这些步骤&#xff0c;并通过代码示例和源码分析来详细解析如何启用和配置Spring Security。 1. 引入Spri…

python 五子棋游戏代码

下面是一个简单的五子棋游戏的Python代码示例。这个示例包括了游戏逻辑和用户界面的基本实现&#xff0c;但并不完整&#xff0c;例如没有AI对战功能。 import numpy as np import pygame # 初始化游戏界面 def init_game(): global board, screen, width, height width,…

微信小程序的view的属性值和用法

在微信小程序中&#xff0c;view 是一个基础的视图组件&#xff0c;用于承载其他视图组件或者展示文本、图片等内容。view 组件具有多种属性&#xff0c;用于控制其行为和样式。以下是一些常用的 view 属性及其用法&#xff1a; class / style: 控制视图的样式&#xff0c;可以…

docker部署Minio对象存储及使用

1.拉取镜像 docker pull minio/minio2.创建数据目录 mkdir -p /data/minio/data3.启动容器 docker run -p 39000:9000 -p 39090:9090 \ --name minio \ -d --restartalways \ -e "MINIO_ACCESS_KEYjyadmin" \ -e "MINIO_SECRET_KEYjyzx2023" \ -v /data…

【八股】Hibernate和JPA:理解它们的关系

在Java开发中&#xff0c;持久化框架是至关重要的工具&#xff0c;它们帮助开发者将Java对象与关系数据库中的数据进行映射和管理。Hibernate和JPA&#xff08;Java Persistence API&#xff09;是两个广泛使用的持久化框架。那么&#xff0c;Hibernate和JPA之间到底是什么关系…

沃通CA根证书获数科网维《商用密码根证书授信证明》

近日&#xff0c;沃通CA三款根证书获数科网维《商用密码根证书授信证明》&#xff0c;将列入数科受信根证书列表并预置到数科文档阅读器。这标志着沃通CA国产化适配能力进一步提升&#xff0c;沃通国产文档签名证书与数科国产文档阅读器兼容互认&#xff0c;能够更好地响应政企…

Nginx编译安装,信号,升级nginx

编译安装nginx&#xff1a;前面博客有写编译安装过程 systemctl stop firewalld setenforce 0 mkdir /data cd /data wget http://nginx.org/download/nginx-1.18.0.tar.gz tar xf nginx-1.18.0.tar.gz cd nginx-1.18.0/ yum -y install make gcc pcre-devel openssl-devel …

揭秘:Java字符串对象的内存分布原理

先来看看下面寄到关于String的真实面试题&#xff0c;看看你废不废&#xff1f; String str1 "Hello"; String str2 "Hello"; String str3 new String("Hello"); String str4 new String("Hello");System.out.println(str1 str2)…

Android 11 Audio strategy配置解析

在启动AudioPolicyService时&#xff0c;通过EngineBase的loadAudioPolicyEngineConfig函数去解析strategy配置。其调用流程如下 接下来就对loadAudioPolicyEngineConfig展开分析 1&#xff0c;解析volume标签 engineConfig::ParsingResult EngineBase::loadAudioPolicyEngine…