從資料庫動態載入樹狀結構選單

by vivid 27. 十二月 2017 16:37

.NET Magazine國際中文電子雜誌
作 者:許薰尹
審 稿:張智凱
文章編號: N171219002
出刊日期: 2017/12/27

在這篇文章中,將要介紹如何在ASP.NET Core MVC專案中,從資料庫動態載入選單項目,並利用一個開放源碼、且支援jQuery的Gijgo tree控制項,套用Bootstrap的樣式以樹狀結構的方式來顯示網站選單。

預設Visual Studio 2017的「ASP.NET Core Web Application」範本專案中,有包含Bootstrap套件與Entity Framework Core套件,可以省略一些套件安裝與設計的步驟,本文將從建立Menu模型開始,然後利用Entity Framework Core Code First建立資料庫結構,最後透過Entity Framework Core查詢出資料表中的選單資料,套用Bootstrap範本,利用Gijgo tree控制項來顯示網站的選單。

Gijgo是一組開放源碼的JavaScript控制項,以jQuery為基礎,可以搭配Bootstrap、Material Design與Font Awesome套件,官網在「http://gijgo.com/」。Gijgo包含多種常見於網站的使用者介面,例如Grid、Tree、Dialog等等。

建立ASP.NET Core MVC專案

1. 啟動Visual Studio 2017開發環境,從Visual Studio開發工具「File」-「New」-「Project」項目,在「New Project」對話盒中,確認視窗上方.NET Framework的目標版本為「.NET Framework 4.6.1」或以上版本,選取左方「Installed」清單-「Templates」-「Visual C#」程式語言,從「.NET Core」分類中,選取「ASP.NET Core Web Application」。設定專案名稱為「TreeDemo」,設定專案存放路徑,然後按下「OK」鍵,請參考下圖所示:

clip_image002

圖 1:建立ASP.NET Core MVC專案。

2. 在「New ASP.NET Core Web Application」對話盒中,確認左上方的清單選取「.NET Core」,右上方的清單ASP.NET Core版本為「ASP.NET Core 2.0」,選取下方的「Web Application ( Model – View – Controller) 」樣版專案,清除勾選下方的「Enable Docker Support」核取方塊,確定右方的「Authentication」項目設定為「No Authentication」,然後按下「OK」按鈕建立專案,請參考下圖所示:

clip_image004

圖 2:建立Web Application ( Model – View – Controller) 」樣版專案。

3. 從「Solution Explorer」視窗 -「Models」資料夾上方,按滑鼠右鍵,從快捷選單選擇「Add」- 「Class」項目,從「Add New Item」對話盒中,選取「Code」分類下的,Class項目,然後在下方將Name設定為「Menu」最後按下「Add」按鈕,請參考下圖所示:

clip_image006

圖 3:加入Menu模型。

4. 在「Menu」類別檔案之中,為「Menu」類別定義「MenuId」、「Title」、「Url」與「ParentMenuId」屬性:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace TreeDemo.Models
{
    public class Menu
    {
        public int MenuId { get; set; }
        public string Title { get; set; }
        public string Url { get; set; }
        public int ParentMenuId { get; set; }

    }
}

 

5. 從Visual Studio 2017開發工具 -「Solution Explorer」視窗 - 「TreeDemo專案」-「Models」資料夾上方按滑鼠右鍵,從快捷選單選擇「Add」- 「New Item」項目,開啟「Add New Item」對話盒,請參考下圖所示:

clip_image008

圖 4:建立控制器。

6. 在「Add New Item」對話盒中選取「Class」項目,設定類別名稱為「MyDbContext」,然後按下「Add 」按鈕,請參考下圖所示:

clip_image010

圖 5 : 加入類別。

7. 在「MyDbContext」類別定義一個「Menu」屬性以透過Entity Framework Core存取資料庫中「Menu」資料表資料:

using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace TreeDemo.Models
{
    public class MyDbContext : DbContext
    {
        public MyDbContext(DbContextOptions<MyDbContext> options)
            : base(options)
        {
        }
        public DbSet<TreeDemo.Models.Menu> Menu { get; set; }
    }
}

 

 

8. 在專案中根目錄下「appsettings.json」檔案,加入設定,儲存資料庫連接字串:

{
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "ConnectionStrings": {
    "MyDbContext": "Server=(localdb)\\mssqllocaldb;Database=MyDbContext;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

 

9. 在專案中根目錄下「Startup.cs」檔案上方引用以下命名空間:

using Microsoft.EntityFrameworkCore;

using TreeDemo.Models;

10. 在專案中根目錄下「Startup.cs」檔案中的「ConfigureServices」方法內加入以下程式碼,以新增服務:

public void ConfigureServices(IServiceCollection services)
      {
          services.AddMvc();

          services.AddDbContext<MyDbContext>(options =>
                  options.UseSqlServer(Configuration.GetConnectionString("MyDbContext")));
      }

11. 選取Visual Studio開發工具「Build」-「Build Solution」編譯目前的專案,確認程式碼能正確編譯。

12. 開啟「Package Manager Console」視窗,在「Solution Explorer」視窗選取專案名稱。從Visual Studio 2017開發工具「Tools」-「NuGet Package Manager」-「Package Manager Console」開啟「Package Manager Console」視窗,然後在提示字元中輸入add-migration指令:

add-migration initial

執行結果參考下圖所示:

clip_image012

圖 6:使用Code First。

接著Visual Studio會在專案中建立一個Migrations資料夾,包含一些C#檔案。其中有一個XXX_initial.cs檔案內容大約如下:

using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using System;
using System.Collections.Generic;

namespace TreeDemo.Migrations
{
    public partial class initial : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "Menu",
                columns: table => new
                {
                    MenuId = table.Column<int>(type: "int", nullable: false)
                        .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
                    ParentMenuId = table.Column<int>(type: "int", nullable: false),
                    Title = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    Url = table.Column<string>(type: "nvarchar(max)", nullable: true)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Menu", x => x.MenuId);
                });
        }

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

 

還有一個MyDbContextModelSnapshot檔案,程式參考如下:

// <auto-generated />
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Storage.Internal;
using System;
using TreeDemo.Models;

namespace TreeDemo.Migrations
{
    [DbContext(typeof(MyDbContext))]
    partial class MyDbContextModelSnapshot : ModelSnapshot
    {
        protected override void BuildModel(ModelBuilder modelBuilder)
        {
#pragma warning disable 612, 618
            modelBuilder
                .HasAnnotation("ProductVersion", "2.0.0-rtm-26452")
                .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);

            modelBuilder.Entity("TreeDemo.Models.Menu", b =>
                {
                    b.Property<int>("MenuId")
                        .ValueGeneratedOnAdd();

                    b.Property<int>("ParentMenuId");

                    b.Property<string>("Title");

                    b.Property<string>("Url");

                    b.HasKey("MenuId");

                    b.ToTable("Menu");
                });
#pragma warning restore 612, 618
        }
    }
}

13. 選取Visual Studio開發工具「Build」-「Build Solution」編譯目前的專案,確認程式碼能正確編譯。

14. 開啟「Package Manager Console」視窗,然後在提示字元中輸入指令,以更新資料庫:

update-database

得到的執行結果如下圖所示:

clip_image014

圖 7:更新資料庫。

預設資料庫會建立在「C:\Users\登入帳號」資料夾中。

15. 開啟「Server Explorer」視窗,在「Data Connections」項目上按滑鼠右鍵,從快捷選單之中選取「Add Connection」項目,請參考下圖所示:

clip_image016

圖 8:連結到資料庫。

16. 若出現「Choose Data Source」視窗,則選擇「Microsoft SQL Server」,然後按「Continue」按鈕,請參考下圖所示:

clip_image018

圖 9:選取SQL Server資料庫。

17. 在「Add Connection」視窗中,設以下屬性,然後按下「OK」按鈕,請參考下圖所示:

l 資料來源 (Data Source) :Microsoft SQL Server (SqlClient)。

l Server name欄位:輸入「(localdb)\mssqllocaldb」。

l Authentication:選取「Windows Authentication」。

l Select or enter a database name欄位:選擇「MyDbContext」資料庫。

clip_image020

圖 10:設定連接資訊。

18. 檢視新建立的資料表與欄位資訊,參考如下:

clip_image022

圖 11:檢視新建立的資料表與欄位資訊。

19. 檢查資料庫結構描述資訊。展開「Server Explorer」視窗-「Data Connections」-「MyDbContext-XXX」資料庫 -「Tables」- 「Menu」資料表,在「Menu」資料表上按滑鼠右鍵,從快捷選單中選取「Show Table Data」顯示資料表所有資料,請參考下圖所示:

clip_image024

圖 12:查詢資料表資料。

20. 參考下圖,新增幾筆資料到資料庫「Menu」資料表:

clip_image026

圖 13:「Menu」資料表中的資料。

安裝Gilgo套件

21. 從「Solution Explorer」- 專案資料夾上方按滑鼠右鍵,從快捷選單選擇「Manage Bower Packages」選項,開啟「Manage Bower Packages」對話盒:

clip_image028

圖 14:開啟「Manage Bower Packages」對話盒。

22. 在「Manage Bower Packages」對話盒點選「Browse」項目,在上方的文字方塊中,輸入「gijgo」關鍵字做搜尋,安裝「gijgo 」1.6.1版本:

clip_image030

圖 15:安裝「gijgo 」1.6.1版本。

Bower會將相依的套件安裝到專案「wwwroot\lib\gijgo」資料夾之中,並在「bower.json」檔案中加入以下設定:

{
  "name": "asp.net",
  "private": true,
  "dependencies": {
    "bootstrap": "3.3.7",
    "jquery": "2.2.0",
    "jquery-validation": "1.14.0",
    "jquery-validation-unobtrusive": "3.2.6",
    "gijgo": "v1.6.1"
  },
  "resolutions": {
    "jquery": ">=1.8"
  }
}

23. 從「Solution Explorer」視窗 -「Models」資料夾上方,按滑鼠右鍵,從快捷選單選擇「Add」- 「Class」項目,從「Add New Item」對話盒中,選取「Code」分類下的,Class項目,然後在下方將Name設定為「TreeNode」最後按下「Add」按鈕

clip_image032

圖 16:加入TreeNode模型。

24. 在「TreeNode」類別檔案之中,為「TreeNode」類別定義「id」、「text」、「imageUrl」與「children」屬性:

public class TreeNode
    {
        public int id { get; set; }
        public string text { get; set; }
        public string imageUrl { get; set; }
        public List<TreeNode> children { get; set; }
    }

25. 在「HomeController」類別宣告一個「MyDbContext」 型別的private變數,將名稱設定為「_context」:

private readonly MyDbContext _context;

26. 在「HomeController」類別加入一個建構函式:

public HomeController(MyDbContext context)
{
    _context = context;
}

27. 在「HomeController」類別加入「GetMenus」與「GetChildNode」方法:

public JsonResult GetMenus()
{
    List<Menu> menuList = _context.Menu.OrderBy(x => x.ParentMenuId).ThenBy(x => x.MenuId).ToList();
    List<TreeNode> siteMenu = menuList.Where(m => m.ParentMenuId == 0).OrderBy(m => m.MenuId)
        .Select(node => new TreeNode
        {
            id = node.MenuId,
            text = node.Title,
            imageUrl= "/images/FolderOptions.ico",
            children = GetChildNode(menuList, node.MenuId)
        }).ToList();

    return this.Json(siteMenu);
}
private List<TreeNode> GetChildNode(List<Menu> menuList, int parentId)
{
    return menuList.Where(l => l.ParentMenuId == parentId).OrderBy(l => l.MenuId)
        .Select(node => new TreeNode
        {
            id = node.MenuId,
            text = node.Title,
            imageUrl = "/images/arrowright.ico",
            children = GetChildNode(menuList, node.MenuId)
        }).ToList();
}

28. 選取Visual Studio開發工具「Build」-「Build Solution」編譯目前的專案,確認程式碼能正確編譯。

29. 按CTRL+F5執行網站首頁(請注意:以下埠號「59492」可能會依據實際上的操作而有所不同,請修改為實際的埠號),然後在瀏覽器輸入以下URL:

http://localhost:59492/Home/GetMenus

此時會得到以下JSON資料:

[{"id":1,"text":"MyWebSite","imageUrl":"/images/FolderOptions.ico","children":[{"id":2,"text":"Home","imageUrl":"/images/arrowright.ico","children":[]},{"id":3,"text":"About","imageUrl":"/images/arrowright.ico","children":[]},{"id":4,"text":"Contact","imageUrl":"/images/arrowright.ico","children":[]}]},{"id":5,"text":"Menus","imageUrl":"/images/FolderOptions.ico","children":[{"id":6,"text":"List","imageUrl":"/images/arrowright.ico","children":[]},{"id":7,"text":"Create","imageUrl":"/images/arrowright.ico","children":[]}]}]

執行結果請參考下圖所示:

clip_image034

圖 17:取得Json資料。

 

30. 修改「\Views\Home\Index」檢視,加入以下程式碼:

@{
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
    <meta name = "viewport" content = "width=device-width" />
    <title>Index</title>
    <script src = "~/lib/jquery/dist/jquery.js"></script>
    <script src = "~/lib/gijgo/dist/modular/js/core.js"></script>
    <link href = "~/lib/gijgo/dist/modular/css/core.css" rel = "stylesheet" />
    <link href = "https://fonts.googleapis.com/icon?family=Material+Icons" rel = "stylesheet" type = "text/css">
    <script src = "~/lib/gijgo/dist/modular/js/tree.js"></script>
    <link href = "~/lib/gijgo/dist/modular/css/tree.css" rel = "stylesheet" />
</head>
<body>
    <div class = "container-fluid">
        <div class = "row">
            <div id = "tree"></div>
        </div>
    </div>
    <script>
        $('#tree').tree({
            dataSource: '/Home/GetMenus'
        });
    </script>
</body>
</html>

31. 按CTRL+F5執行網站首頁(請注意:以下埠號「59492」可能會依據實際上的操作而有所不同,請修改為實際的埠號),然後在瀏覽器輸入以下URL:

http://localhost:59492/Home/Index

執行結果請參考下圖所示:

clip_image036

圖 18:Tree選單。

Tags:

.NET Core | .NET Magazine國際中文電子雜誌 | ASP.NET Core MVC | C# | 許薰尹Vivid Hsu

新增評論




  Country flag
biuquote
  • 評論
  • 線上預覽
Loading






NET Magazine國際中文電子雜誌

NET Magazine國際中文電子版雜誌,由恆逸資訊創立於2000,自發刊日起迄今已發行超過500篇.NET相關技術文章,擁有超過40000名註冊讀者群。NET Magazine國際中文電子版雜誌希望藉於電子雜誌與NET Developer達到共同學習與技術新知分享,歡迎每一位對.NET 技術有興趣的朋友們多多支持本雜誌,讓作者群們可以有持續性的動力繼續爬文。<請加入免費訂閱>

月分類Month List