生成项目
通过用官网的来生成 Get Started | ABP.IO 配上官网地址,需要注意的是,数据库选择Mysql
选择完成后,执行页面上的两条命令
dotnet tool install -g Volo.Abp.Cli
abp new Acme.BookStore -dbms MySQL -csf
生成结束后的内容
单击打开
更改 数据库连接 DbMigrator 模块与Web 模块中的 appsettings.json
"Default": "Server=localhost;Port=3306;Database=BookStore;Uid=root;Pwd=123456;"
到这里基本完成
Book应用
实体类
启动模板中的领域层分为两个项目:
Acme.BookStore.Domain
包含你的实体, 领域服务和其他核心域对象.Acme.BookStore.Domain.Shared
包含可与客户共享的常量,枚举或其他域相关对象.
在解决方案的领域层(Acme.BookStore.Domain
项目)中定义你的实体.
该应用程序的主要实体是Book
. 在Acme.BookStore.Domain
项目中创建一个 Books
文件夹(命名空间),并在其中添加名为 Book
的类,如下所示:
using System;
using Volo.Abp.Domain.Entities.Auditing;
namespace Acme.BookStore.Books
{
public class Book : AuditedAggregateRoot<Guid>
{
public string Name { get; set; }
public BookType Type { get; set; }
public DateTime PublishDate { get; set; }
public float Price { get; set; }
}
}
Book
实体使用了BookType
枚举. 在Acme.BookStore.Domain.Shared
项目中创建Books
文件夹(命名空间),并在其中添加BookType
:
namespace Acme.BookStore.Books
{
public enum BookType
{
Undefined,
Adventure,
Biography,
Dystopia,
Fantastic,
Horror,
Science,
ScienceFiction,
Poetry
}
}
将Book实体添加到DbContext中
EF Core需要你将实体和 DbContext
建立关联.最简单的做法是在Acme.BookStore.EntityFrameworkCore
项目的BookStoreDbContext
类中添加DbSet
属性.如下所示:
public class BookStoreDbContext : AbpDbContext<BookStoreDbContext>
{
public DbSet<Book> Books { get; set; }
//...
}
将Book实体映射到数据库表
打开BookStoreDbContext
类的OnModelCreating
方法,为Book
实体添加映射代码:
using Acme.BookStore.Books;
...
namespace Acme.BookStore.EntityFrameworkCore
{
public class BookStoreDbContext :
AbpDbContext<BookStoreDbContext>,
IIdentityDbContext,
ITenantManagementDbContext
{
...
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
/* Include modules to your migration db context */
builder.ConfigurePermissionManagement();
...
/* Configure your own tables/entities inside here */
builder.Entity<Book>(b =>
{
b.ToTable(BookStoreConsts.DbTablePrefix + "Books",
BookStoreConsts.DbSchema);
b.ConfigureByConvention(); //auto configure for the base class props
b.Property(x => x.Name).IsRequired().HasMaxLength(128);
});
}
}
}
添加数据迁移
如果你使用Visual Studio, 你也许想要在包管理控制台(PMC)中使用
Add-Migration Created_Book_Entity -c BookStoreDbContext
和Update-Database -Context BookStoreDbContext
命令. 确保Acme.BookStore.Web
是启动项目并且Acme.BookStore.EntityFrameworkCore
是 PMC 的默认项目.
注意:这里会出现 这个错误,在模块中导入 Microsoft.EntityFrameworkCore.Design 包就好了,在web 与 dbmigrator中都要导入,选择与自己版本相对的版本
导入完成后再执行就可以了
刷新数据库 ,可以看到里面已经存在了 bookstore 数据库与表
添加种子数据
在 *.Domain
项目下创建 IDataSeedContributor
的派生类,并且拷贝以下代码:
using System;
using System.Threading.Tasks;
using Acme.BookStore.Books;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
namespace Acme.BookStore
{
public class BookStoreDataSeederContributor
: IDataSeedContributor, ITransientDependency
{
private readonly IRepository<Book, Guid> _bookRepository;
public BookStoreDataSeederContributor(IRepository<Book, Guid> bookRepository)
{
_bookRepository = bookRepository;
}
public async Task SeedAsync(DataSeedContext context)
{
if (await _bookRepository.GetCountAsync() <= 0)
{
await _bookRepository.InsertAsync(
new Book
{
Name = "1984",
Type = BookType.Dystopia,
PublishDate = new DateTime(1949, 6, 8),
Price = 19.84f
},
autoSave: true
);
await _bookRepository.InsertAsync(
new Book
{
Name = "The Hitchhiker's Guide to the Galaxy",
Type = BookType.ScienceFiction,
PublishDate = new DateTime(1995, 9, 27),
Price = 42.0f
},
autoSave: true
);
}
}
}
}
更新数据库
运行 Acme.BookStore.DbMigrator
应用程序来更新数据库:
把这个模块设为启动项目,直接运行,然后去看数据库。
创建应用程序
应用程序层由两个分离的项目组成:
Acme.BookStore.Application.Contracts
包含你的DTO和应用服务接口.Acme.BookStore.Application
包含你的应用服务实现.
在本部分中,你将创建一个应用程序服务,使用ABP Framework的 CrudAppService
基类来获取,创建,更新和删除书籍.
BookDto
CrudAppService
基类需要定义实体的基本DTO. 在 Acme.BookStore.Application.Contracts
项目中创建 Books
文件夹(命名空间), 并在其中添加名为 BookDto
的DTO类:
using System;
using Volo.Abp.Application.Dtos;
namespace Acme.BookStore.Books
{
public class BookDto : AuditedEntityDto<Guid>
{
public string Name { get; set; }
public BookType Type { get; set; }
public DateTime PublishDate { get; set; }
public float Price { get; set; }
}
}
- DTO类被用来在 表示层 和 应用层 传递数据.参阅DTO文档.
- 为了在用户界面上展示书籍信息,
BookDto
被用来将书籍数据传递到表示层. BookDto
继承自AuditedEntityDto<Guid>
.与上面定义的Book
实体一样具有一些审计属性.
在将书籍返回到表示层时,需要将Book
实体转换为BookDto
对象. AutoMapper库可以在定义了正确的映射时自动执行此转换. 启动模板配置了AutoMapper,因此你只需在Acme.BookStore.Application
项目的BookStoreApplicationAutoMapperProfile
类中定义映射:
using Acme.BookStore.Books;
using AutoMapper;
namespace Acme.BookStore
{
public class BookStoreApplicationAutoMapperProfile : Profile
{
public BookStoreApplicationAutoMapperProfile()
{
CreateMap<Book, BookDto>();
}
}
}
CreateUpdateBookDto
在Acme.BookStore.Application.Contracts
项目中创建 Books
文件夹(命名空间),并在其中添加名为 CreateUpdateBookDto
的DTO类:
using System;
using System.ComponentModel.DataAnnotations;
namespace Acme.BookStore.Books
{
public class CreateUpdateBookDto
{
[Required]
[StringLength(128)]
public string Name { get; set; }
[Required]
public BookType Type { get; set; } = BookType.Undefined;
[Required]
[DataType(DataType.Date)]
public DateTime PublishDate { get; set; } = DateTime.Now;
[Required]
public float Price { get; set; }
}
}
- 这个DTO类被用于在创建或更新书籍的时候从用户界面获取图书信息.
- 它定义了数据注释特性(如
[Required]
)来定义属性的验证规则. DTO由ABP框架自动验证.
就像上面的BookDto
一样,创建一个从CreateUpdateBookDto
对象到Book
实体的映射,最终映射配置类如下:
using Acme.BookStore.Books;
using AutoMapper;
namespace Acme.BookStore
{
public class BookStoreApplicationAutoMapperProfile : Profile
{
public BookStoreApplicationAutoMapperProfile()
{
CreateMap<Book, BookDto>();
CreateMap<CreateUpdateBookDto, Book>();
}
}
}
IBookAppService
下一步是为应用程序定义接口,在Acme.BookStore.Application.Contracts
项目创建 Books
文件夹(命名空间),并在其中添加名为IBookAppService
的接口:
using System;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Acme.BookStore.Books
{
public interface IBookAppService :
ICrudAppService< //Defines CRUD methods
BookDto, //Used to show books
Guid, //Primary key of the book entity
PagedAndSortedResultRequestDto, //Used for paging/sorting
CreateUpdateBookDto> //Used to create/update a book
{
}
}
- 框架定义应用程序服务的接口不是必需的. 但是,它被建议作为最佳实践.
ICrudAppService
定义了常见的CRUD方法:GetAsync
,GetListAsync
,CreateAsync
,UpdateAsync
和DeleteAsync
. 从这个接口扩展不是必需的,你可以从空的IApplicationService
接口继承并手动定义自己的方法(将在下一部分中完成).ICrudAppService
有一些变体, 你可以在每个方法中使用单独的DTO(例如使用不同的DTO进行创建和更新).
BookAppService
是时候实现IBookAppService
接口了.在Acme.BookStore.Application
项目中创建 Books
文件夹(命名空间),并在其中添加名为 BookAppService
的类:
using System;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
namespace Acme.BookStore.Books
{
public class BookAppService :
CrudAppService<
Book, //The Book entity
BookDto, //Used to show books
Guid, //Primary key of the book entity
PagedAndSortedResultRequestDto, //Used for paging/sorting
CreateUpdateBookDto>, //Used to create/update a book
IBookAppService //implement the IBookAppService
{
public BookAppService(IRepository<Book, Guid> repository)
: base(repository)
{
}
}
}
BookAppService
继承了CrudAppService<...>
.它实现了ICrudAppService
定义的CRUD方法.BookAppService
注入IRepository <Book,Guid>
,这是Book
实体的默认仓储. ABP自动为每个聚合根(或实体)创建默认仓储. 请参阅仓储文档BookAppService
使用IObjectMapper将Book
对象转换为BookDto
对象, 将CreateUpdateBookDto
对象转换为Book
对象. 启动模板使用AutoMapper库作为对象映射提供程序. 我们之前定义了映射, 因此它将按预期工作.
Swagger UI
启动模板配置为使用Swashbuckle.AspNetCore运行swagger UI. 运行应用程序并在浏览器中输入https://localhost:XXXX/swagger/
(用你自己的端口替换XXXX)作为URL. 使用CTRL+F5
运行应用程序 (Acme.BookStore.Web
)并使用浏览器访问https://localhost:<port>/swagger/
on your browser. 使用你自己的端口号替换 <port>
.
你会看到一些内置的服务端点和Book
服务,它们都是REST风格的端点: