從零開始Blazor Server(2)--整合資料庫

2022-07-28 12:02:34

開篇

上一篇文章我們留了個尾巴,沒有把freesql整合進去,這篇文章我們來整合。


目前的思路呢,是做一個簡單的四不像的RABC,也有使用者、角色、

許可權三部分。

但是其中每個使用者只有一個角色,即使用者和角色之間是一多關係。每個角色可以有多個許可權,即許可權跟角色之間是多多關係。


這樣主要是想說一下freesql怎麼做一多和多多關係。一個正常的RABC使用者和角色之間也應該是多多,並且使用者可能跟許可權也可以有直接的聯絡。但是這個是一樣的,只要許可權列表拿到了,後面就隨便怎麼處理了。

建表

這次我們只建立四個表UserRolePermissionRolePermisson

採用CodeFirst的方式,優先建立Entity,使用Freesql的資料庫同步功能生成表結構。


User表:

[Description("使用者資訊表")]
public class UserEntity : BaseEntity<UserEntity, int>
{
    [Description("使用者名稱")]
    public string? UserName { get; set; }

    [Description("密碼")]
    public string? Password { get; set; }

    [Description("使用者姓名")]
    public string? Name { get; set; }

    [Description("角色Id")]
    public int RoleId { get; set; }

    [Description("角色")]
    [Navigate(nameof(RoleId))]
    public RoleEntity? Role { get; set; }
}

藉著User表解釋一下。

  • 繼承了BaseEntity<UserEntity, int>以後,會新增一個int型別的Id,這個Id是自增的。同時還會自動生成CreateTimeUpdateTimeIsDeletedSort四個欄位,這些都是BaseEntity自帶的功能,使用BaseEntity在查詢的時候會自動攜帶IsDeleted標識,讓我們可以輕鬆軟刪除。

  • Description標籤在Freesql裡可以自動生成註釋,由於sqlite不支援註釋,所以這裡沒有用,單純是作為註釋來使用。

  • FreeSql的一多關係,這裡是一的部分,使用起來很簡單,有一個RoleId,然後定義一個RoleEntity,標籤裡用Navigate指定通過RoleId來查詢就行了。

Role表:

[Description("角色表")]
public class RoleEntity : BaseEntity<RoleEntity, int>
{
    [Description("角色名稱")]
    public string? Name { get; set; }

    [Description("使用者")]
    [Navigate(nameof(UserEntity.RoleId))]
    public virtual ICollection<UserEntity>? Users { get; set; }

    [Description("許可權")]
    [Navigate(ManyToMany = typeof(RolePermissionEntity))]
    public virtual ICollection<PermissionEntity>? Permissions { get; set; }
}
  • Users是使用者角色一多關係的多的部分,我們只需要指定成ICollectionList也可以。使用Navigate指定關聯的名字為RoleId就可以了。這裡需要注意的是一定是關聯RoleId不是User表的Id,關聯錯了的話這裡的關係就亂掉了。

  • Permissions是角色許可權多多關係的處理部分,屬性寫起來跟一多關係一樣,但是Navigate標籤裡不再是繫結一個字串了,而是用ManyToMany指定一個type,這個type是我們多多關係的中間表。這個表我們下面講。

RolePermission

[Description("角色許可權多多關係表")]
public class RolePermissionEntity : BaseEntity<RolePermissionEntity, Guid>
{
    [Description("角色Id")]
    public int RoleId { get; set; }

    [Description("角色")]
    [Navigate(nameof(RoleId))]
    public RoleEntity? Role { get; set; }

    [Description("許可權Id")]
    public int PermissionId { get; set; }

    [Description("許可權")]
    [Navigate(nameof(PermissionId))]
    public PermissionEntity? Permission { get; set; }
}
  • 嚴格來說,這個表不應該使用BaseEntity的模式,因為它應該是一個聯合主鍵,不應該有個自增主鍵,並且也不需要那些CreateTimeUpdateTimeIsDeletedSort。但是這裡為了省事,就直接用了,只是把主鍵型別改成了Guid,反正我們也不會使用這玩意來排序查詢。也不會影響頻繁刪除的情況下可能出現的溢位問題。

  • 別的沒什麼好說的,就是兩個屬性RoleIdPermissionId就i行了,如果用不著它,那Entity都可以不加。

Permission

[Description("許可權表")]
public class PermissionEntity: BaseEntity<PermissionEntity, int>
{
    [Description("許可權名")]
    public string? Name { get; set; }

    [Description("對應頁面Url")]
    public string? Url { get; set; }
    
    [Description("角色")]
    [Navigate(ManyToMany = typeof(RolePermissionEntity))]
    public virtual ICollection<RoleEntity>? Roles { get; set; }
}

這個表沒什麼好說的了,就是一個多多關係,跟Role的是一樣的。

新增FreeSql

之前我們只是新增了FreeSql的包,沒有掛進程式裡,現在我們把它弄到程式裡去。


首先我們把連線字串整到組態檔裡去,比如我放在

"Db": {
    "ConnString": "Data Source=|DataDirectory|\\document.db; Pooling=true;Min Pool Size=1"
  },

這樣我們就可以在任何位置 用var conn = Furion.App.Configuration["Db:ConnString"];獲取到連線字串了。


然後我們需要建立一個freesql的範例

        var freeSql = new FreeSqlBuilder()
            .UseAutoSyncStructure(Furion.App.WebHostEnvironment.IsDevelopment())
            .UseConnectionString(DataType.Sqlite, conn)
            .Build();

這裡的UseAutoSyncStructure是是否開啟自動遷移,如果開啟了,freesql用的時候發現沒有表或者表結構不對,就自動遷移表結構,這個東西生產上不建議用,所以我們就只有在Development的時候使用。


然後我們的Entity都有Entity字尾,這個放到資料庫裡不好看,我們就把它給去掉

freeSql.Aop.ConfigEntity += (s, e) =>
        {
            e.ModifyResult.Name = e.EntityType.Name.Replace("Entity", "");
        };

另外如果你需要加字首,或者改大小寫,改下劃線都可以在這裡金信處理。


因為我們使用的是BaseEntity模式,所以這裡需要初始化

BaseEntity.Initialization(freeSql, null);

最後我們還需要新增一些預設的使用者,角色,許可權

        if (!UserEntity.Where(x => x.UserName == "Admin").Any())
        {
            UserEntity user = new UserEntity()
            {
                UserName = "Admin",
                Password = MD5Encryption.Encrypt("Admin"),
                Name = "張三"
            };
            user.Save();
            

            PermissionEntity homePermission = new PermissionEntity()
            {
                Name = "首頁",
                Url = "/"
            };
            homePermission.Save();
            
            PermissionEntity userPermission = new PermissionEntity()
            {
                Name = "使用者管理",
                Url = "/User"
            };
            userPermission.Save();
            
            RoleEntity role = new RoleEntity()
            {
                Name = "管理員",
                Users = new List<UserEntity>() { user },
                Permissions = new List<PermissionEntity>(){homePermission, userPermission}
            };
            role.Save().SaveMany(nameof(RoleEntity.Users));
            role.SaveMany(nameof(RoleEntity.Permissions));
        }

這裡需要注意,如果有多表的部分需要連其他的表一起更新,那就需要主動呼叫SaveMany方法,如果不呼叫,那麼不會自動更新。


原始碼在github:https://github.com/j4587698/BlazorLearn,分支lesson2。