目录
1、创建书籍实体
2、将书籍实体添加到DbContext
3、配置Book实体
4、添加新的迁移并更新数据库
5、添加初始(样本)数据
6、创建应用程序服务
7、在浏览器的开发人员控制台中进行测试
8、创建书籍页面
9、将书籍页面添加到主菜单
10、本地化菜单项
11、图书清单
启动模板中的域层分为两个项目:
ABPBookStore.Domain
包含您的实体,域服务和其他核心域对象。ABPBookStore.Domain.Shared
包含那些能够与客户共享的constants
,enums
或其他领域相关的对象。在解决方案的域层(Acme.BookStore.Domain
项目)中定义实体。应用程序的主要实体是Book
。在Acme.BookStore.Domain
项目中创建一个名为 Book
的类,如下所示:
using System;
using Volo.Abp.Domain.Entities.Auditing;
namespace ABPBookStore
{
public class Book : AuditedAggregateRoot
{
public string Name { get; set; }
public BookType Type { get; set; }
public DateTime PublishDate { get; set; }
public float Price { get; set; }
protected Book()
{
}
public Book(Guid id, string name, BookType type, DateTime publishDate, float price) :
base(id)
{
Name = name;
Type = type;
PublishDate = publishDate;
Price = price;
}
}
}
AggregateRoot(
聚合根)
和Entity
。聚合根是域驱动设计(DDD)概念之一。Book
实体继承AuditedAggregateRoot
它在AggregateRoot
类顶部增加了一些审核性质(CreationTime
,CreatorId
,LastModificationTime
...等)。Guid
是Book
实体的主键类型。BookType枚举
在ABPBookStore.Domain.Shared
项目中创建枚举BookType:
namespace ABPBookStore
{
public enum BookType
{
Undefined,
Adventure,
Biography,
Dystopia,
Fantastic,
Horror,
Science,
ScienceFiction,
Poetry
}
}
EF Core要求将实体与您的DbContext
关联。最简单的方法是在ABPBookStore.EntityFrameworkCore
项目的ABPBookStoreDbContext
类中添加一个DbSet
属性,如下所示:
public DbSet
在ABPBookStore.EntityFrameworkCore
项目中打开ABPBookStoreDbContextModelCreatingExtensions.cs
文件,并将以下代码添加到ConfigureBookStore
方法的末尾以配置Book实体:
builder.Entity
{
b.ToTable(ABPBookStoreConsts.DbTablePrefix + "Books", ABPBookStoreConsts.DbSchema);
b.ConfigureByConvention(); //auto configure for the base class props
b.Property(x => x.Name).IsRequired().HasMaxLength(128);
});
并添加相应引用
启动模板使用EF Core Code First Migrations来创建和维护数据库架构。在菜单>工具> NuGet软件包管理器下打开软件包管理器控制台(PMC)
选择ABPBookStore.EntityFrameworkCore.DbMigrations
作为默认项目并执行以下命令:
Add-Migration "Created_Book_Entity"
这将在ABPBookStore.EntityFrameworkCore.DbMigrations
项目的Migrations
文件夹内创建一个新的迁移类。然后执行Update-Database
命令以更新数据库架构:
Update-Database
命令已在数据库中创建AppBooks
表。打开数据库并输入一些示例行,这样就可以在列表页面上显示它们。
INSERT INTO AppBooks (Id,CreationTime,Name,Type,PublishDate,Price) VALUES
('f3c04764-6bfd-49e2-859e-3f9bfda6183e', '2018-07-01', '1984',3,'1949-06-08','19.84');
INSERT INTO AppBooks (Id,CreationTime,Name,Type,PublishDate,Price) VALUES
('13024066-35c9-473c-997b-83cd8d3e29dc', '2018-07-01', 'The Hitchhiker`s Guide to the Galaxy',7,'1995-09-27','42');
INSERT INTO AppBooks (Id,CreationTime,Name,Type,PublishDate,Price) VALUES
('4fa024a1-95ac-49c6-a709-6af9e4d54b54', '2018-07-02', 'Pet Sematary',5,'1983-11-14','23.7');
下一步是创建一个应用程序服务来管理图书,这将使我们具有四个基本功能:创建,阅读,更新和删除。应用程序层分为两个项目:
ABPBookStore.Application.Contracts
主要包含您的DTO
和应用程序服务接口。ABPBookStore.Application
包含您的应用程序服务的实现。BookDto
在ABPBookStore.Application.Contracts
项目中创建一个命名为BookDto的DTO类:
namespace ABPBookStore
{
public class BookDto : AuditedEntityDto
{
public string Name { get; set; }
public BookType Type { get; set; }
public DateTime PublishDate { get; set; }
public float Price { get; set; }
}
}
BookDto
用于将书籍数据传输到表示层,以便在UI上显示书籍信息。BookDto
从AuditedEntityDto
派生,其具有审核属性,就像上面定义的Book
类一样。在将书籍返回到表示层时,需要将Book
实体映射到BookDto
对象。当您定义正确的映射时,AutoMapper库可以自动执行此转换。启动模板配置了AutoMapper,因此您只需在ABPBookStore.Application
项目的ABPBookStoreApplicationAutoMapperProfile
类中定义映射即可:
public ABPBookStoreApplicationAutoMapperProfile()
{
CreateMap
}
CreateUpdateBookDto
在
ABPBookStore.Application.Contracts
项目中创建一个名为CreateUpdateBookDto
的DTO类:
public class CreateUpdateBookDto
{
[Required]
[StringLength(128)]
public string Name { get; set; }
[Required]
public BookType Type { get; set; } = BookType.Undefined;
[Required]
public DateTime PublishDate { get; set; }
[Required]
public float Price { get; set; }
}
DTO
用于在创建或更新书籍时从用户界面获取书籍信息。[Required]
)来定义对属性的验证。DTO
会由ABP框架自动验证。接下来,使用以下命令添加ABPBookStoreApplicationAutoMapperProfile
从CreateUpdateBookDto
对象到Book
实体的映射CreateMap
:
public ABPBookStoreApplicationAutoMapperProfile()
{
CreateMap
CreateMap
}
IBookAppService
在ABPBookStore.Application.Contracts
项目中创建一个名为IBookAppService
的接口:
using System;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace ABPBookStore
{
public interface IBookAppService :
ICrudAppService< //Defines CRUD methods
BookDto, //Used to show books
Guid, //Primary key of the book entity
PagedAndSortedResultRequestDto, //Used for paging/sorting on getting a list of books
CreateUpdateBookDto, //Used to create a new book
CreateUpdateBookDto> //Used to update a book
{
}
}
ICrudAppService
定义了通用CRUD方法:GetAsync
,GetListAsync
,CreateAsync
,UpdateAsync
和DeleteAsync
。不需要扩展。相反,您可以从空IApplicationService
接口继承并手动定义自己的方法。ICrudAppService
对于每种方法,可以在其中使用单独的DTO 有所不同。BookAppService
在Acme.BookStore.Application项目中以BookAppService实现IBookAppService
using System;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
namespace ABPBookStore
{
public class BookAppService :
CrudAppService
IBookAppService
{
public BookAppService(IRepository
: base(repository)
{
}
}
}
BookAppService
派生自CrudAppService<...>
,它实现了上面定义的所有CRUD(创建,读取,更新,删除)方法。BookAppService
注入IRepository
这是Book
实体的默认存储库。ABP自动为每个聚合根(或实体)创建默认存储库。BookAppService使用
IObjectMapper,
将Book
对象映射到BookDto
对象以及将CreateUpdateBookDto
对象映射到Book
对象。启动模板使用AutoMapper库作为对象映射提供程序。我们之前已经定义了映射,因此它将按预期工作。您可以使用喜欢的浏览器的开发者控制台轻松测试JavaScript代理。运行应用程序,打开浏览器的开发人员工具(Chrome的快捷方式是F12),切换到“ 控制台”选项卡,键入以下代码,然后按Enter:
aBPBookStore.book.getList({}).done(function (result) { console.log(result); });
aBPBookStore
是BookAppService的命名空间
转换为camelCase的名称空间。book
是的常规名称BookAppService
(删去AppService
后缀并转换为camelCase)。getList
是AsyncCrudAppService
基类中GetListAsync
定义的方法的常规名称(删除Async
后缀并转换为camelCase)。{}
参数用于将空对象发送到GetListAsync
方法,该方法通常需要一个PagedAndSortedResultRequestDto
用于将分页和排序选项发送到服务器的类型的对象(所有属性都是可选的,因此您可以发送空对象)。getList
函数返回一个promise
。您可以将回调传递给done
(或then
)函数,以从服务器获取结果。让我们使用create
函数创建一本新书:
检查Books
数据库中的表以查看新书行。可以试试get
,update
和delete
功能。
这时候应该创建可见的和可用的东西了!代替经典的MVC,我们将使用Microsoft建议的新的Razor Pages UI方法。
在ABPBookStore.Web
项目Pages
文件夹下创建文件夹Books。
右键单击“ Books”文件夹,然后选择“ 添加”>“ Razor页面”菜单项,以添加新的Razor页面。命名为Index,
打开Index.cshtml
并更改整个内容,如下所示
@page
@using ABPBookStore.Web.Pages.Books
@inherits ABPBookStore.Web.Pages.ABPBookStorePage
@model IndexModel
Books
注:这个地方不知道为什么没有自动生成的ABPBookStorePage类,所以在
ABPBookStore.Web
项目Pages
文件夹下创建ABPBookStorePage.cs,修改代码如下
using ABPBookStore.Localization;
using Microsoft.AspNetCore.Mvc.Localization;
using Microsoft.AspNetCore.Mvc.Razor.Internal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
namespace ABPBookStore.Web.Pages
{
public abstract class ABPBookStorePage : AbpPage
{
[RazorInject]
public IHtmlLocalizer
}
}
此代码更改了Razor视图页面模型的默认继承,因此它继承自ABPBookStorePage
该类(而不是PageModel
)。ABPBookStorePage
启动模板随附的类提供了所有页面使用的一些共享属性/方法。
在Index.cshtml.cs中
将IndexModel
的命名空间设置为ABPBookStore.Pages.Books
。
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace ABPBookStore.Web.Pages.Books
{
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
}
打开文件夹Menus
中的ABPBookStoreMenuContributor
类,并将以下代码添加到ConfigureMainMenuAsync
方法的末尾:
context.Menu.AddItem(
new ApplicationMenuItem("BooksStore", l["Menu:BookStore"])
.AddItem(
new ApplicationMenuItem("BooksStore.Books", l["Menu:Books"], url: "/Books")
)
);
本地化文本位于ABPBookStore.Domain.Shared
项目的Localization/ABPBookStore
文件夹下:
打开en.json
文件,并将以下本地化文本添加到文件末尾:
{
"culture": "en",
"texts": {
"Menu:Home": "Home",
"Welcome": "Welcome",
"LongWelcomeMessage": "Welcome to the application. This is a startup project based on the ABP framework. For more information, visit abp.io.",
"Menu:BookStore": "Book Store",
"Menu:Books": "Books",
"Actions": "Actions",
"Edit": "Edit",
"PublishDate": "Publish date",
"NewBook": "New book",
"Name": "Name",
"Type": "Type",
"Price": "Price",
"CreationTime": "Creation time",
"AreYouSureToDelete": "Are you sure you want to delete this item?"
}
}
Menu:
为菜单项添加前缀以区别于其他文本。如果未在本地化文件中定义文本,则文本将回退到本地化键(作为ASP.NET Core的标准行为)。我们将使用Datatables.net jQuery插件显示图书清单。数据表可以通过AJAX完全工作,它快速,流行并且提供了良好的用户体验。Datatables插件是在启动模板中配置的,因此您可以在任何页面中直接使用它,而无需在页面中包含任何样式或脚本文件。
Index.cshtml
更改Pages/Books/Index.cshtml
如下:
@page
@inherits ABPBookStore.Web.Pages.ABPBookStorePage
@model ABPBookStore.Web.Pages.Books.IndexModel
@section scripts
{
}
@L["Books"]
@L["Name"]
@L["Type"]
@L["PublishDate"]
@L["Price"]
@L["CreationTime"]
abp-script
标记帮助程序用于将外部脚本添加到页面。与标准script
标签相比,它具有许多其他功能。它处理缩小和版本控制。abp-card
和abp-table
是Twitter Bootstrap card组件的标签帮助器。ABP中还有其他有用的标签帮助程序,可以轻松使用大多数引导程序组件。您也可以使用常规HTML标记代替这些标记帮助器,但是使用标记帮助器可以减少HTML代码并通过IntelliSense和编译时类型检查来防止错误。添加脚本文件
在该Pages/Books/
文件夹下创建JavaScript文件index.js
:
index.js
内容如下所示:
$(function () {
var dataTable = $('#BooksTable').DataTable(abp.libs.datatables.normalizeConfiguration({
ajax: abp.libs.datatables.createAjax(aBPBookStore.book.getList),
columnDefs: [
{ data: "name" },
{ data: "type" },
{ data: "publishDate" },
{ data: "price" },
{ data: "creationTime" }
]
}));
});