😎完善初始化种子数据流程(限定程序集和执行顺序)

This commit is contained in:
zuohuaijun 2025-06-05 23:14:45 +08:00
parent 03d438436c
commit a72a4095e9
13 changed files with 168 additions and 43 deletions

View File

@ -10,9 +10,11 @@ public class DataInitItemOutput
{
public string Name { get; set; }
public int Count { get; set; }
public string AssemblyName { get; set; }
public int Order { get; set; }
public int Count { get; set; }
public string Description { get; set; }
}

View File

@ -6,9 +6,25 @@
namespace Admin.NET.Core.Service;
public class InitTableSeedDataInput
public class InitTableInput
{
public string ConfigId { get; set; }
public List<string> EntityNames { get; set; }
}
public class InitSeedDataInput
{
public string ConfigId { get; set; }
public List<SeedType> SeedNames { get; set; }
}
public class SeedType
{
public string Name { get; set; }
public string AssemblyName { get; set; }
public int Order { get; set; }
}

View File

@ -567,7 +567,15 @@ public class SysDatabaseService : IDynamicApiController, ITransient
var seedData = ((IEnumerable)hasDataMethod?.Invoke(instance, null))?.Cast<object>().ToArray() ?? [];
var entityType = seedDataType.GetInterfaces().First().GetGenericArguments().First();
outputList.Add(new DataInitItemOutput() { Name = seedDataType.Name, Count = seedData.Length, AssemblyName = seedDataType.Assembly.ManifestModule.Name, Description = entityType.GetCustomAttribute<SugarTable>().TableDescription + "种子数据" });
var seedDataAtt = seedDataType.GetCustomAttribute<SeedDataAttribute>();
outputList.Add(new DataInitItemOutput()
{
Name = seedDataType.Name,
AssemblyName = seedDataType.Assembly.ManifestModule.Name,
Order = seedDataAtt != null ? seedDataAtt.Order : 0,
Count = seedData.Length,
Description = entityType.GetCustomAttribute<SugarTable>().TableDescription + "种子数据"
});
}
return outputList;
}
@ -577,7 +585,7 @@ public class SysDatabaseService : IDynamicApiController, ITransient
/// </summary>
/// <param name="input"></param>
[DisplayName("初始化表结构")]
public void InitTable(InitTableSeedDataInput input)
public void InitTable(InitTableInput input)
{
if (!_userManager.SuperAdmin)
throw Oops.Oh("只有超管才可以操作!");
@ -591,13 +599,13 @@ public class SysDatabaseService : IDynamicApiController, ITransient
/// </summary>
/// <param name="input"></param>
[DisplayName("初始化种子数据")]
public void InitSeedData(InitTableSeedDataInput input)
public void InitSeedData(InitSeedDataInput input)
{
if (!_userManager.SuperAdmin)
throw Oops.Oh("只有超管才可以操作!");
var dbProvider = _db.AsTenant().GetConnectionScope(input.ConfigId);
SqlSugarSetup.InitSeedData(dbProvider, false, input.EntityNames);
SqlSugarSetup.InitSeedData(dbProvider, false, input.SeedNames);
}
/// <summary>

View File

@ -524,8 +524,8 @@ public static class SqlSugarSetup
/// </summary>
/// <param name="dbProvider"></param>
/// <param name="enableIncreSeed"></param>
/// <param name="entityNames"></param>
public static void InitSeedData(SqlSugarScopeProvider dbProvider, bool enableIncreSeed, List<string> entityNames = null)
/// <param name="seedTypes"></param>
public static void InitSeedData(SqlSugarScopeProvider dbProvider, bool enableIncreSeed, List<SeedType> seedTypes = null)
{
var config = dbProvider.CurrentConnectionConfig;
@ -536,9 +536,19 @@ public static class SqlSugarSetup
.WhereIF(enableIncreSeed, u => u.IsDefined(typeof(IncreSeedAttribute), false))
.OrderBy(u => u.GetCustomAttributes(typeof(SeedDataAttribute), false).Length > 0 ? ((SeedDataAttribute)u.GetCustomAttributes(typeof(SeedDataAttribute), false)[0]).Order : 0).ToList();
// 过滤指定实体
if (entityNames != null && entityNames.Count > 0)
seedDataTypes = seedDataTypes.Where(u => entityNames.Contains(u.Name)).ToList();
// 过滤指定程序集种子
if (seedTypes != null && seedTypes.Count > 0)
{
seedTypes = seedTypes.OrderBy(u => u.Order).ToList();
var tmpSeedTypes = new List<Type>();
foreach (var seedType in seedTypes)
{
var tmpSeedType = seedDataTypes.FirstOrDefault(u => u.Name == seedType.Name && u.Assembly.ManifestModule.Name == seedType.AssemblyName);
if (tmpSeedType != null) tmpSeedTypes.Add(tmpSeedType);
}
if (tmpSeedTypes.Count > 0)
seedDataTypes = tmpSeedTypes;
}
// 由于种子数据在应用层存在重写,必须保证应用层种子最后执行(多线程顺序会乱)
int taskIndex = 0, size = seedDataTypes.Count;

View File

@ -106,7 +106,7 @@
"prettier": "^3.5.3",
"rollup-plugin-visualizer": "^6.0.1",
"sass": "^1.89.1",
"terser": "^5.40.0",
"terser": "^5.41.0",
"typescript": "^5.8.3",
"vite": "^6.3.5",
"vite-plugin-cdn-import": "^1.0.1",

View File

@ -30,7 +30,8 @@ import { DbColumnInput } from '../models';
import { DbTableInput } from '../models';
import { DeleteDbColumnInput } from '../models';
import { DeleteDbTableInput } from '../models';
import { InitTableSeedDataInput } from '../models';
import { InitSeedDataInput } from '../models';
import { InitTableInput } from '../models';
import { UpdateDbColumnInput } from '../models';
import { UpdateDbTableInput } from '../models';
/**
@ -592,11 +593,11 @@ export const SysDatabaseApiAxiosParamCreator = function (configuration?: Configu
/**
*
* @summary 🔖
* @param {InitTableSeedDataInput} [body]
* @param {InitSeedDataInput} [body]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
apiSysDatabaseInitSeedDataPost: async (body?: InitTableSeedDataInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
apiSysDatabaseInitSeedDataPost: async (body?: InitSeedDataInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/api/sysDatabase/initSeedData`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
@ -640,11 +641,11 @@ export const SysDatabaseApiAxiosParamCreator = function (configuration?: Configu
/**
*
* @summary 🔖
* @param {InitTableSeedDataInput} [body]
* @param {InitTableInput} [body]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
apiSysDatabaseInitTablePost: async (body?: InitTableSeedDataInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
apiSysDatabaseInitTablePost: async (body?: InitTableInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/api/sysDatabase/initTable`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
@ -1133,11 +1134,11 @@ export const SysDatabaseApiFp = function(configuration?: Configuration) {
/**
*
* @summary 🔖
* @param {InitTableSeedDataInput} [body]
* @param {InitSeedDataInput} [body]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysDatabaseInitSeedDataPost(body?: InitTableSeedDataInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
async apiSysDatabaseInitSeedDataPost(body?: InitSeedDataInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
const localVarAxiosArgs = await SysDatabaseApiAxiosParamCreator(configuration).apiSysDatabaseInitSeedDataPost(body, options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
@ -1147,11 +1148,11 @@ export const SysDatabaseApiFp = function(configuration?: Configuration) {
/**
*
* @summary 🔖
* @param {InitTableSeedDataInput} [body]
* @param {InitTableInput} [body]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysDatabaseInitTablePost(body?: InitTableSeedDataInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
async apiSysDatabaseInitTablePost(body?: InitTableInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
const localVarAxiosArgs = await SysDatabaseApiAxiosParamCreator(configuration).apiSysDatabaseInitTablePost(body, options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
@ -1365,21 +1366,21 @@ export const SysDatabaseApiFactory = function (configuration?: Configuration, ba
/**
*
* @summary 🔖
* @param {InitTableSeedDataInput} [body]
* @param {InitSeedDataInput} [body]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysDatabaseInitSeedDataPost(body?: InitTableSeedDataInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
async apiSysDatabaseInitSeedDataPost(body?: InitSeedDataInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
return SysDatabaseApiFp(configuration).apiSysDatabaseInitSeedDataPost(body, options).then((request) => request(axios, basePath));
},
/**
*
* @summary 🔖
* @param {InitTableSeedDataInput} [body]
* @param {InitTableInput} [body]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysDatabaseInitTablePost(body?: InitTableSeedDataInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
async apiSysDatabaseInitTablePost(body?: InitTableInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
return SysDatabaseApiFp(configuration).apiSysDatabaseInitTablePost(body, options).then((request) => request(axios, basePath));
},
/**
@ -1577,23 +1578,23 @@ export class SysDatabaseApi extends BaseAPI {
/**
*
* @summary 🔖
* @param {InitTableSeedDataInput} [body]
* @param {InitSeedDataInput} [body]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof SysDatabaseApi
*/
public async apiSysDatabaseInitSeedDataPost(body?: InitTableSeedDataInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
public async apiSysDatabaseInitSeedDataPost(body?: InitSeedDataInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
return SysDatabaseApiFp(this.configuration).apiSysDatabaseInitSeedDataPost(body, options).then((request) => request(this.axios, this.basePath));
}
/**
*
* @summary 🔖
* @param {InitTableSeedDataInput} [body]
* @param {InitTableInput} [body]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof SysDatabaseApi
*/
public async apiSysDatabaseInitTablePost(body?: InitTableSeedDataInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
public async apiSysDatabaseInitTablePost(body?: InitTableInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
return SysDatabaseApiFp(this.configuration).apiSysDatabaseInitTablePost(body, options).then((request) => request(this.axios, this.basePath));
}
/**

View File

@ -26,18 +26,24 @@ export interface DataInitItemOutput {
*/
name?: string | null;
/**
* @type {string}
* @memberof DataInitItemOutput
*/
assemblyName?: string | null;
/**
* @type {number}
* @memberof DataInitItemOutput
*/
order?: number;
/**
* @type {number}
* @memberof DataInitItemOutput
*/
count?: number;
/**
* @type {string}
* @memberof DataInitItemOutput
*/
assemblyName?: string | null;
/**
* @type {string}
* @memberof DataInitItemOutput

View File

@ -259,7 +259,8 @@ export * from './icontainer';
export * from './icustom-attribute-provider';
export * from './idisposable';
export * from './isite';
export * from './init-table-seed-data-input';
export * from './init-seed-data-input';
export * from './init-table-input';
export * from './int-ptr';
export * from './invoice-info';
export * from './invoice-key-info';
@ -363,6 +364,7 @@ export * from './schedule-input';
export * from './schema-serialization-mode';
export * from './search';
export * from './security-rule-set';
export * from './seed-type';
export * from './send-subscribe-message-input';
export * from './serialization-format';
export * from './set-nick-name-input';

View File

@ -0,0 +1,35 @@
/* tslint:disable */
/* eslint-disable */
/**
* Admin.NET
* .NET <br/><u><b><font color='FF0000'> 👮</font></b></u>
*
* OpenAPI spec version: 1.0.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
import { SeedType } from './seed-type';
/**
*
*
* @export
* @interface InitSeedDataInput
*/
export interface InitSeedDataInput {
/**
* @type {string}
* @memberof InitSeedDataInput
*/
configId?: string | null;
/**
* @type {Array<SeedType>}
* @memberof InitSeedDataInput
*/
seedNames?: Array<SeedType> | null;
}

View File

@ -16,19 +16,19 @@
*
*
* @export
* @interface InitTableSeedDataInput
* @interface InitTableInput
*/
export interface InitTableSeedDataInput {
export interface InitTableInput {
/**
* @type {string}
* @memberof InitTableSeedDataInput
* @memberof InitTableInput
*/
configId?: string | null;
/**
* @type {Array<string>}
* @memberof InitTableSeedDataInput
* @memberof InitTableInput
*/
entityNames?: Array<string> | null;
}

View File

@ -0,0 +1,40 @@
/* tslint:disable */
/* eslint-disable */
/**
* Admin.NET
* .NET <br/><u><b><font color='FF0000'> 👮</font></b></u>
*
* OpenAPI spec version: 1.0.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
/**
*
*
* @export
* @interface SeedType
*/
export interface SeedType {
/**
* @type {string}
* @memberof SeedType
*/
name?: string | null;
/**
* @type {string}
* @memberof SeedType
*/
assemblyName?: string | null;
/**
* @type {number}
* @memberof SeedType
*/
order?: number;
}

View File

@ -133,7 +133,7 @@ export interface SysLogDiff {
businessData?: string | null;
/**
*
*
*
* @type {string}
* @memberof SysLogDiff

View File

@ -137,6 +137,7 @@ const optionsSeed = useVxeTable(
{ type: 'seq', title: '序号', width: 50, fixed: 'left' },
{ field: 'name', title: '种子名称', showOverflow: 'tooltip', align: 'left' },
{ field: 'description', title: '描述', showOverflow: 'tooltip', align: 'left' },
{ field: 'order', title: '执行顺序', showOverflow: 'tooltip' },
{ field: 'count', title: '种子个数', showOverflow: 'tooltip', slots: { default: 'row_count' } },
{ field: 'assemblyName', title: '所属程序集', showOverflow: 'tooltip', align: 'left' },
],
@ -186,7 +187,11 @@ const handleInitSeedData = async () => {
try {
const params = {
configId: state.configId,
entityNames: state.seedSelectedRows.map((row) => row.name),
seedNames: state.seedSelectedRows.map((row) => ({
name: row.name,
assemblyName: row.assemblyName,
order: row.order,
})),
};
await getAPI(SysDatabaseApi).apiSysDatabaseInitSeedDataPost(params);
ElMessage.success('生成种子数据操作成功');