好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

ABP框架(.netCore+angular)的初步使用——启动并建立操作表

关于ABP框架我就不多说了,网上资料很多,可以自行百度。直接进入 官网

 

选择你需要的核心框架。我选择了angular+.netCore 版本。点击创建模板,等待下载完成。

在使用vs打开项目前,你应该确保vs是2017版本及以上,还需要安装了.netCore相关的组件。

打开: 下载目录\MyDemo\5.1.1\aspnet-core 下的解决方案。重新生成解决方案,会自动更新NuGet包。设置web.host项目为启动项,修改数据库链接字符串

 

 

 PM窗口下执行 update-database 命令,将会在指定数据库中进行数据迁移,也就是建立了系统表。

 

 

 至此,就可以运行项目了。如果想启动angular的话,先下载好node.js,使用管理员权限打开node.js command prompt 命令窗体,执行CD /d “”目录“  进入到 :下载目录\MyDemo\5.1.1\angular 的工程目录里,执行npm install

加载好相关包后,执行npm start。关于node.js的知识,这里不展开了,我也不是很懂。

 

 

 如果成功的话,最后会显示监听的端口,打开该地址前,要确保后端的项目接口可以使用,我们先用调试模式去运行项目。效果如下

 

 

 打开 http://localhost:4200地址,使用Admin账号,密码123qwe,登录后界面如下

 

 

 第一步大功告成。接下来看看后端项目的结构。

为了减少复杂性和提高代码的可重用性,采用分层架构是一种被广泛接受的技术。
为了实现分层的体系结构,ABP遵循 DDD(领域驱动设计) 的原则,将分为四个层次:

展现层( Presentation ) :提供一个用户界面,实现用户交互操作。 应用层(Application) :进行展现层与领域层之间的协调,协调业务对象来执行特定的应用程序的任务。它不包含业务逻辑。 领域层(Domain) :包括业务对象和业务规则,这是应用程序的核心层。 基础设施层(Infrastructure) :提供通用技术来支持更高的层。例如基础设施层的仓储(Repository)可通过ORM来实现数据库交互。

Presentation对应了客户端angular,应用层对应项目MyDemo.Application,领域层对应MyDemo.Core,基础设施层对应MyDemo.EntityFrameworkCore,

创建实体

一个简单的应用场景:创建一些任务(tasks)并分配给人。 我们需要 Task 和 Person 这两个实体。

在领域层建立一个文件夹,取名为Demo,在这里建立这两个实体

     public   enum   TaskState
    {
        Finish,
        Active
    } 

 public   class  Task : Entity< long > 
    {
        [ForeignKey(  "  AssignedPersonId  "  )]
          public   virtual  Person AssignedPerson {  get ;  set  ; }

          public   virtual   int ? AssignedPersonId {  get ;  set  ; }

          public   virtual   string  Description {  get ;  set  ; }

          public   virtual  DateTime CreationTime {  get ;  set  ; }

          public   virtual  TaskState State {  get ;  set  ; }

          public   Task()
        {
            CreationTime  =  DateTime.Now;
            State  =  TaskState.Active;
        }
    } 

     public   class   Person : Entity
    {
          public   virtual   string  Name {  get ;  set  ; }
    } 

我们导航到Entity 和Entity<long>

     public   abstract   class  Entity : Entity< int >, IEntity, IEntity< int > 
    {
          protected   Entity();
    }

      public   abstract   class  Entity<TPrimaryKey> : IEntity<TPrimaryKey> 
    {
          protected   Entity();

          // 
         //   摘要:
          //       Unique identifier for this entity. 
         public   virtual  TPrimaryKey Id {  get ;  set  ; }

          //
          public   virtual   bool  EntityEquals( object   obj);
          // 
         //   摘要:
          //       Checks if this entity is transient (it has not an Id).
          // 
         //   返回结果:
          //       True, if this entity is transient 
         public   virtual   bool   IsTransient();
          public   override   string   ToString();
    } 

可以了解到Entity有一个Id属性,默认int,可以改成你想要的数据类型。

在MyDemo.EntityFrameworkCore项目下找到MyProjectDbContext.cs,添加DBset,命名应该和数据库的表名称一致,为了区分系统表最好不要加上ABP

  执行命令 Add-Migration InitialCreate,记得是在EntityFrammeworkCore项目下。成功后会出现一个新文件

 

 

 在该文件下修改成如下代码

         protected   override   void   Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                 //  表名 
               name:  "  Person  "  ,
                 //  Column,字段名 
               columns: table =>  new  
               {
                   Id  = table.Column< int >(nullable:  false  ),
                   Name  = table.Column< string >(nullable:  false  ),
               },
                 //  约束,这里只有一个主键约束 
               constraints: table => 
               {
                   table.PrimaryKey(  "  PK_Person  " , x =>  x.Id);
               });

            migrationBuilder.CreateTable(
                 //  表名 
               name:  "  Task  "  ,
                 //  Column,字段名 
               columns: table =>  new  
               {
                   Id  = table.Column< int >(nullable:  false  ),
                   AssignedPersonId  = table.Column< int ?>(nullable:  true  ),
                   Description  = table.Column< string >(nullable:  false  ),
                   CreationTime  = table.Column<DateTime>(nullable:  false  ),
                   State  = table.Column< int >(nullable:  false  ),
               },
                 //  约束,这里只有一个主键约束 
               constraints: table => 
               {
                   table.PrimaryKey(  "  PK_Task  " , x =>  x.Id);
               });
        }

          protected   override   void   Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                          name:   "  Person  "  );
            migrationBuilder.DropTable(
              name:   "  Task  "  );
        }
    } 

在程序包管理器控制台中输入命令:Update-Database,就可以在数据库中看到Person和Task表;

创建仓储

定义仓储接口的代码写到Core项目中,因为仓储接口是领域层的一部分。

 

 

 这里不需要定义Person的仓储, ABP提供了一种注入通用仓储的方式, ,除非你需要自定义方法,大部分情况下默认接口里的方法已经够用了

 

 ITaskRepository.cs代码如下,

     public   interface  ITaskRepository :IRepository<Task,  long > 
    {
List<Task> GetAllWithPeople(int? assignedPersonId, TaskState? state); }

 

 定义仓储实现类

 

 

     public   class  TaskRepository: MyDemoRepositoryBase<Task,  long > , ITaskRepository
    {
          public  TaskRepository(IDbContextProvider<MyDemoDbContext> dbContextProvider) :  base  (dbContextProvider)
        {
        }
          public  List<Task> GetAllWithPeople( int ? assignedPersonId, TaskState?  state)
        {
              //  在仓储方法中,不用处理数据库连接、DbContext和数据事务,ABP框架会自动处理。 

             var  query = GetAll();  //  GetAll() 返回一个 IQueryable<T>接口类型

              //  添加一些Where条件 

             if   (assignedPersonId.HasValue)
            {
                query  = query.Where(task => task.AssignedPerson.Id ==  assignedPersonId.Value);
            }

              if   (state.HasValue)
            {
                query  = query.Where(task => task.State ==  state);
            }

              return   query
                .OrderByDescending(task  =>  task.CreationTime)
                .Include(task  =>  task.AssignedPerson)
                .ToList();
        }
    } 

创建应用服务

 

 

 在MyDemo.Application项目下建立应用服务和交互类Dto

代码如下

     public   interface   IPersonAppService : IApplicationService
    {
          //  定义一个方法 
        List<GetAllPersonOutPut>  GetAllPerson();
    } 

     public   class   TaskAppService : MyDemoAppServiceBase, ITaskAppService
    {
          private   readonly   ITaskRepository _taskRepository;
          private   readonly  IRepository<Person>  _personRepository;

          ///   <summary> 
         ///   构造函数自动注入我们所需要的类或接口
          ///   </summary> 
         public  TaskAppService(ITaskRepository taskRepository, IRepository<Person>  personRepository)
        {
            _taskRepository  =  taskRepository;
            _personRepository  =  personRepository;
        }

          public  List<Task>  GetTasks(GetTasksInput input)
        {
              //  调用Task仓储的特定方法GetAllWithPeople 
             var  tasks =  _taskRepository.GetAllWithPeople(input.AssignedPersonId, input.State);

              //  用AutoMapper自动将List<Task>转换成List<TaskDto> 
             return   tasks;
        }

          public   void   UpdateTask(UpdateTaskInput input)
        {
              //  可以直接Logger,它在ApplicationService基类中定义的 
            Logger.Info( "  Updating a task for input:   "  +  input);

              //  通过仓储基类的通用方法Get,获取指定Id的Task实体对象 
             var  task =  _taskRepository.Get(input.TaskId);

              //  修改task实体的属性值 
             if   (input.State.HasValue)
            {
                task.State  =  input.State.Value;
            }

              if   (input.AssignedPersonId.HasValue)
            {
                task.AssignedPerson  =  _personRepository.Load(input.AssignedPersonId.Value);
            }

              //  我们都不需要调用Update方法
              //  因为应用服务层的方法默认开启了工作单元模式(Unit of Work)
              //  ABP框架会工作单元完成时自动保存对实体的所有更改,除非有异常抛出。有异常时会自动回滚,因为工作单元默认开启数据库事务。 
         }

          public   void   CreateTask(CreateTaskInput input)
        {
            Logger.Info(  "  Creating a task for input:   "  +  input);

              //  通过输入参数,创建一个新的Task实体 
             var  task =  new  Task { Description =  input.Description };

              if   (input.AssignedPersonId.HasValue)
            {
                task.AssignedPersonId  =  input.AssignedPersonId.Value;
            }

              //  调用仓储基类的Insert方法把实体保存到数据库中 
             _taskRepository.Insert(task);
        }
    } 

     public   class   UpdateTaskInput 
    {
        [Range(  1 ,  long  .MaxValue)]
          public   long  TaskId {  get ;  set  ; }

          public   int ? AssignedPersonId {  get ;  set  ; }

          public  TaskState? State {  get ;  set  ; }

          public   void  AddValidationErrors(List<ValidationResult>  results)
        {
              if  (AssignedPersonId ==  null  && State ==  null  )
            {
                results.Add(  new  ValidationResult( "  AssignedPersonId和State不能同时为空!  " ,  new [] {  "  AssignedPersonId  " ,  "  State  "   }));
            }
        }
    } 

     public   class   GetTasksInput
    {

          public   virtual   int ? AssignedPersonId {  get ;  set  ; }

          public   virtual  TaskState State {  get ;  set  ; }
    } 

     public   class   CreateTaskInput 
    {
          public   int ? AssignedPersonId {  get ;  set  ; }

        [Required]
          public   string  Description {  get ;  set  ; }
    } 

必须注意的是大部分的类都需要用public,像TaskAppServicel类前面如果不用public的话就无法暴露出这个接口,仓储不用public的话自动依赖注入就会报错。

启动项目就可以看到刚写的服务出现在了界面上

 

 测试一下

 

 这里执行后出现了错误,但调试的项目并没有抛出异常,应该是被捕获到了。查看log日志

 

 

 这里数据主键没有设置自增键,去数据设置一下,重新测试,OK,查询数据,确实增加了一条数据。Update-Database命令前修改的InitialCreate类里面的up方法,应该可以在这里设置自增键,下次有空再补上。

ABP的大致应用就是这样了,后面在慢慢探索其他功能。下期的话应该会写一下.netCore怎么在IIS上部署,前几天弄了一下午总发布报错,后面有时间在继续研究。

 

   

查看更多关于ABP框架(.netCore+angular)的初步使用——启动并建立操作表的详细内容...

  阅读:53次