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)並分配給人。 我們需要TaskPerson這兩個實體。

在領域層建立一個文件夾,取名為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上部署,前幾天弄了一下午總發布報錯,后面有時間在繼續研究。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM