造轮子之种子数据

在前面我们基本把应用框架的基础设施搭建完成。接下来我们就得着手处理一下种子数据的问题。

在一个基础框架里面,种子数据很重要,比如一些基础数据,初始用户等等,这些都需要初始化,否则程序启动却无法使用就很尴尬了。

IDataSeeder

首先定义一个种子数据接口

csharp 复制代码
using Wheel.DependencyInjection;

namespace Wheel.DataSeeders
{
    public interface IDataSeeder : ITransientDependency
    {
        Task Seed(CancellationToken cancellationToken = default);
    }
}

接下来所有的种子数据实现都需要继承这个接口。

DataSeederExtensions

封装一个扩展方法,获取所有IDataSeeder的实现,并执行数据初始化。

csharp 复制代码
namespace Wheel.DataSeeders
{
    public static class DataSeederExtensions
    {
        public static async Task<IApplicationBuilder> SeedData(this IApplicationBuilder app) 
        {
            var dataSeeders = app.ApplicationServices.GetServices<IDataSeeder>();

            foreach (var dataSeeder in dataSeeders)
            {
                await dataSeeder.Seed();
            }
            return app;
        }
    }
}

在Program中添加代码

csharp 复制代码
var app = builder.Build();

//初始化种子信息
await app.SeedData();

这样就初步完成了种子数据的配置。

实现种子数据

接下来就实现一些种子数据。

用户角色种子数据

IdentityDataSeeder

csharp 复制代码
using Microsoft.AspNetCore.Identity;
using Wheel.Domain;
using Wheel.Domain.Identity;

namespace Wheel.DataSeeders.Identity
{
    public class IdentityDataSeeder : IDataSeeder
    {
        private readonly IBasicRepository<Role, string> _roleRepository;
        private readonly IBasicRepository<User, string> _userRepository;
        private readonly UserManager<User> _userManager;
        private readonly IUserStore<User> _userStore;
        private readonly RoleManager<Role> _roleManager;

        public IdentityDataSeeder(IBasicRepository<Role, string> roleRepository, IBasicRepository<User, string> userRepository, UserManager<User> userManager, IUserStore<User> userStore, RoleManager<Role> roleManager)
        {
            _roleRepository = roleRepository;
            _userRepository = userRepository;
            _userManager = userManager;
            _userStore = userStore;
            _roleManager = roleManager;
        }

        public async Task Seed(CancellationToken cancellationToken = default)
        {
            if (!await _roleRepository.AnyAsync(a => a.Name == "admin"))
            {
                await _roleManager.CreateAsync(new Role("admin", Enums.RoleType.Admin));
            }
            if (!await _roleRepository.AnyAsync(a => a.Name == "user"))
            {
                await _roleManager.CreateAsync(new Role("user", Enums.RoleType.App));
            }

            if (!await _userRepository.AnyAsync(a => a.UserName == "admin"))
            {
                var adminUser = new User();
                await _userStore.SetUserNameAsync(adminUser, "admin", cancellationToken);

                var emailStore = (IUserEmailStore<User>)_userStore;
                await emailStore.SetEmailAsync(adminUser, "136590076@qq.com", cancellationToken);
                await _userManager.CreateAsync(adminUser, "Wheel@2023");
                await _userManager.AddToRoleAsync(adminUser, "admin");
                await _userManager.UpdateAsync(adminUser);
            }
        }
    }
}

这里初始化一个普通User角色和管理后台admin角色,以及一个admin角色的账号。

多语言种子数据

LocalizationDataSeeder

csharp 复制代码
using Wheel.Domain;
using Wheel.Domain.Localization;

namespace Wheel.DataSeeders.Localization
{
    public class LocalizationDataSeeder : IDataSeeder
    {
        private readonly IBasicRepository<LocalizationCulture, int> _localizationCultureRepository;

        public LocalizationDataSeeder(IBasicRepository<LocalizationCulture, int> localizationCultureRepository)
        {
            _localizationCultureRepository = localizationCultureRepository;
        }

        public async Task Seed(CancellationToken cancellationToken = default)
        {
            if (!(await _localizationCultureRepository.AnyAsync(cancellationToken)))
            {
                await _localizationCultureRepository.InsertAsync(new LocalizationCulture() { Name = "en" }, true);
                await _localizationCultureRepository.InsertAsync(new LocalizationCulture() { Name = "zh-CN"}, true);
            }
        }
    }
}

这里给多语言初始化两种国家语言。

菜单种子

MenuDataSeeder

csharp 复制代码
using Wheel.Domain;
using Wheel.Domain.Menus;

namespace Wheel.DataSeeders.Identity
{
    public class MenuDataSeeder : IDataSeeder
    {
        private readonly IBasicRepository<Menu, Guid> _menuRepository;

        public MenuDataSeeder(IBasicRepository<Menu, Guid> menuRepository)
        {
            _menuRepository = menuRepository;
        }

        public async Task Seed(CancellationToken cancellationToken = default)
        {
            if (!(await _menuRepository.AnyAsync(cancellationToken)))
            {
                await _menuRepository.InsertAsync(new Menu
                {
                    Name = "SystemManage",
                    DisplayName = "系统管理",
                    Sort = 99,
                    Id = Guid.NewGuid(),
                    Icon = "SettingOutlined",
                    Path = "/System",
                    MenuType = Enums.MenuType.Menu,
                    Children = new List<Menu>
                    {
                        new Menu
                        {
                            Name = "UserManage",
                            DisplayName = "用户管理",
                            Sort = 0,
                            Id = Guid.NewGuid(),
                            Path = "/System/User",
                            MenuType = Enums.MenuType.Page
                        },
                        new Menu
                        {
                            Name = "RoleManage",
                            DisplayName = "角色管理",
                            Sort = 1,
                            Id = Guid.NewGuid(),
                            Path = "/System/Role",
                            MenuType = Enums.MenuType.Page,
                        },
                        new Menu
                        {
                            Name = "PermissionManage",
                            DisplayName = "权限管理",
                            Sort = 2,
                            Id = Guid.NewGuid(),
                            Path = "/System/Permission",
                            MenuType = Enums.MenuType.Page
                        },
                        new Menu
                        {
                            Name = "MenuManage",
                            DisplayName = "菜单管理",
                            Sort = 3,
                            Id = Guid.NewGuid(),
                            Path = "/System/Menu",
                            MenuType = Enums.MenuType.Page
                        },
                        new Menu
                        {
                            Name = "LocalizationManage",
                            DisplayName = "多语言管理",
                            Sort = 4,
                            Id = Guid.NewGuid(),
                            Path = "/System/Localization",
                            MenuType = Enums.MenuType.Page
                        },
                    }
                }, true, cancellationToken: cancellationToken);
            }
        }
    }
}

这里菜单初始化基础管理后台页面所需的菜单。

启动程序后,打开数据库



可以看到数据初始化成功。

这样就轻轻松松完成了我们种子数据的实现。

轮子仓库地址https://github.com/Wheel-Framework/Wheel

欢迎进群催更。

相关推荐
暴走约伯17 小时前
【VFX工具链源码拆解 09】终极工业化闭环:基于 ID 规则驱动的全自动场景建档、骨骼挂载与男转女场景迁移
unity·c#·游戏引擎·材质
用户788477316342 天前
WinForms 迁移 WPF:Upgrade Assistant 覆盖 30%,剩下 70% 我手写了六周
c#
寂寞的船2 天前
【Unity知识速递】第13期 Unity 内存泄漏排查实战:从 Memory Profiler 到 Lua 引用泄漏的生产级全链路诊断
unity·junit·c#·游戏引擎·lua
用户3721574261352 天前
C# 提取 PDF 附件:包括文档附件和页面注释附件
c#
寂寞的船2 天前
【Unity Bug挑战】第12期 Awaitable 二次 await 死锁之谜 —— 为什么同一个异步操作等两次就卡死?
unity·c#·游戏引擎·bug
huaqianzkh4 天前
WinForm C#:循环修改控件UI闪烁卡顿?SuspendLayout / ResumeLayout 与 BeginUpdate 优化
开发语言·ui·c#
用户3721574261355 天前
C# 实现 Excel 单元格保护:锁定公式并允许编辑指定区域
c#·ai编程·编程语言
公子小六5 天前
基于.NET的Windows窗体编程之WinForms数据持久化(1)
windows·microsoft·c#·.net·winforms
三雷科技5 天前
第6章第4节:自定义分词器
开发语言·c#
zhanghaha13145 天前
C# 系列教程_12 字符串 string 保姆级系统教程(面向新手,大量示例 + 原理讲解)
开发语言·数据库·c#