• 从零开始Blazor Server(2)--整合数据库


    开篇

    上一篇文章我们留了个尾巴,没有把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以后,会添加一个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? Users { get; set; }
    
        [Description("权限")]
        [Navigate(ManyToMany = typeof(RolePermissionEntity))]
        public virtual ICollection? 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? 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() { user },
                    Permissions = new List(){homePermission, userPermission}
                };
                role.Save().SaveMany(nameof(RoleEntity.Users));
                role.SaveMany(nameof(RoleEntity.Permissions));
            }
    折叠

    这里需要注意,如果有多表的部分需要连其他的表一起更新,那就需要主动调用SaveMany方法,如果不调用,那么不会自动更新。


    源码在github:https://github.com/j4587698/BlazorLearn,分支lesson2。

  • 相关阅读:
    Location的匹配
    IO学习系列之阻塞IO
    cdh集群搭建(6.3)
    jdk17新特性
    SpringBoot SpringBoot 开发实用篇 6 监控 6.4 info 端点指标控制
    BI-SQL丨MEGRE
    GBASE 8s事务配置参数
    OpenMV与Arduino通信—串口
    [Java]SPI扩展功能
    算法----BF算法&KMP算法
  • 原文地址:https://www.cnblogs.com/j4587698/p/16527556.html