ABP框架入门学习(二)——实体层/领域层/应用层实现

上篇文章写到下载模板,模板的结构简单介绍、生成数据库和基础数据,然后并运行了项目,接下来咋们说说项目的扩展,新建一块自己的业务,参照现有的项目架构,我们该怎么一步步增加自己的功能?

一、创建Book实体

前面有说道项目领域层是有两块组成:

  • TestApp.BookStore.Domain包含你的实体领域服务和其他核心域对象.
  • TestApp.BookStore.Domain.Shared包含可与客户共享的常量,枚举或其他域相关对象

TestApp.BookStore.Domain创建一个Books的文件夹,并添加一个Book的基础类,如下图:

 

 

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Domain.Entities.Auditing;

namespace TestApp.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; }
    }
}
View Code

 

  • ABP为实体提供了两个基本的基类: AggregateRootEntityAggregate Root领域驱动设计 概念之一. 可以视为直接查询和处理的根实体.
  • Book实体继承了AuditedAggregateRoot,AuditedAggregateRoot类在AggregateRoot类的基础上添加了一些基础审计属性(例如CreationTimeCreatorIdLastModificationTime 等). ABP框架自动为你管理这些属性.
  • GuidBook实体的主键类型.

由于Book实体包含BookType枚举,所以在TestApp.BookStore.Domain.Shared创建一个Books的文件夹,并添加一个BookType的基础类,如下图:

 

 

 

using System;
using System.Collections.Generic;
using System.Text;

namespace TestApp.BookStore.Books
{
    public enum BookType
    {
        Undefined,
        Adventure,
        Biography,
        Dystopia,
        Fantastic,
        Horror,
        Science,
        ScienceFiction,
        Poetry
    }
}
View Code

 

二、将Book实体添加到DbContext中并映射到数据库表中

EF Core需要你将实体和 DbContext 建立关联.做法是在TestApp.BookStore.EntityFrameworkCore项目的BookStoreDbContext

 

 

 

添加DbSet属性.如下所示:

 public DbSet<Book> Books { get; set; }


OnModelCreating方法,为Book实体添加映射代码:

 builder.Entity<Book>(b =>
        {
            b.ToTable(BookStoreConsts.DbTablePrefix + "Books",BookStoreConsts.DbSchema);
            b.ConfigureByConvention();
            b.Property(x => x.Name).IsRequired().HasMaxLength(128);
        });
  • BookStoreConsts 含有用于表的架构和表前缀的常量值. 使用它不是强制的,但建议在统一的地方控制表前缀.
  • ConfigureByConvention() 方法优雅的配置/映射继承的属性,应对所有的实体使用它.

可在数据模型添加初始化数据方便学习ABP Framework功能,如下图(可忽略)

在 TestApp.BookStore.Domain项目下创建 IDataSeedContributor 的派生类

 

 

 

using System;
using System.Threading.Tasks;
using TestApp.BookStore.Books;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;

namespace TestApp.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
                );
            }
        }
    }
}
View Code

 

  • 如果数据库中当前没有图书,则此代码使用 IRepository<Book, Guid>(默认repository)将两本书插入数据库.


三、更新数据库

由于数据表结构和初始化数据调整,所以需要更新下数据库,将TestApp.BookStore.DbMigrator应用程序设为启动项目,来更新数据库,运行完成会发现数据库book表会多两条默认数据,如下图:

 

 

 

  • .DbMigrator 是一个控制台使用程序,可以在开发生产环境迁移数据库架构初始化种子数据.

四、创建应用程序

前面也说道应用程序跟领域层类似都有两块组成:

  • TestApp.BookStore.Application.Contracts 包含你的DTO应用服务接口.
  • TestApp.BookStore.Application 包含你的应用服务实现.

创建一个应用程序服务,使用ABP Framework的 CrudAppService 基类来获取,创建,更新和删除书籍.

CrudAppService 基类需要定义实体的基本DTO.

 

在  TestApp.BookStore.Application.Contracts 项目中创建 Books 文件夹(命名空间),添加 BookDto 的DTO类:

using System;
using System.Collections.Generic;
using System.Text;
using Volo.Abp.Application.Dtos;


namespace TestApp.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类被用来在 表示层 和 应用层 传递数据.
  • 为了在用户界面上展示书籍信息,BookDto被用来将书籍数据传递到表示层.
  • BookDto继承自 AuditedEntityDto<Guid>.与上面定义的 Book 实体一样具有一些审计属性.

在将书籍返回到表示层时,需要将Book实体转换为BookDto对象. AutoMapper库可以在定义了正确的映射时自动执行此转换. 启动模板配置了AutoMapper,因此你只需在TestApp.BookStore.Application项目的BookStoreApplicationAutoMapperProfile类中定义映射:

 

 

        CreateMap<Book, BookDto>();

 

TestApp.BookStore.Application.Contracts项目中创建 Books 文件夹(命名空间),并在其中添加名为 CreateUpdateBookDto 的DTO类:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;

namespace TestApp.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实体的映射,最终映射配置类如下:

            CreateMap<CreateUpdateBookDto, Book>();

 

TestApp.BookStore.Application.Contracts项目中创建 Books 文件夹(命名空间),并在其中添加名为IBookAppService接口:

using System;
using System.Collections.Generic;
using System.Text;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;

namespace TestApp.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,UpdateAsyncDeleteAsync. 从这个接口扩展不是必需的,你可以从空的IApplicationService接口继承并手动定义自己的方法(将在下一部分中完成).
  • ICrudAppService有一些变体, 你可以在每个方法中使用单独的DTO(例如使用不同的DTO进行创建和更新).

TestApp.BookStore.Application.Contracts项目新增文件内容如下图:

 

在TestApp.BookStore.Application项目中创建 Books 文件夹(命名空间),并在其中添加名为 BookAppService 的类实现IBookAppService接口:

 

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;

namespace TestApp.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
    {
        public BookAppService(IRepository<Book, Guid> repositoty)
            : base(repositoty)
        {
        }
    }
}

五、自动生成API Controllers

在典型的ASP.NET Core应用程序中,你创建API Controller以将应用程序服务公开为HTTP API端点. 这将允许浏览器或第三方客户端通过HTTP调用它们.

ABP可以自动按照约定将你的应用程序服务配置为MVC API控制器.

六、运行Swagger UI测试API

运行应用程序并在浏览器中输入https://localhost:XXXX/swagger/(用你自己的端口替换XXXX)作为URL. 使用CTRL+F5运行应用程序 (TestApp.BookStore.Web)并使用浏览器访问https://localhost:<port>/swagger/

 

可以尝试执行[GET] /api/app/book API来获取书籍列表, 服务端会返回以下JSON结果:

 

 

到现在为止新增的Book模块基本完成,下片接着介绍如何操作Book的增删改查功能......

 

posted @ 2022-02-23 11:47  HI_Hub_MI  阅读(977)  评论(0编辑  收藏  举报