通过读取 JSON 配置文件的方式来生成 material_config.json,并允许程序根据指定的 JSON 文件名称动态生成配置

将当前的 Test 方法中的硬编码配置(如 connectionString, joins, config)改为通过读取 JSON 配置文件的方式来生成 material_config.json,并允许程序根据指定的 JSON 文件名称动态生成配置。这样可以进一步减少硬编码,提高灵活性和可维护性。以下,我将基于你的要求修改代码,保持现有功能(如动态枚举、AdditionalColumns 配置、IsShow 默认 true 等),并实现从 JSON 文件加载配置。


需求分析

1. 当前情况

  • 硬编码:

    • connectionString:数据库连接字符串。

    • joins:JoinConfig 列表,定义表连接。

    • config:GeneratorConfig 对象,包含 Id, Name, EnumArray, Fields, MainTable, RequiredFields, HiddenFields, Tabs, EnumFields, AdditionalColumns。

  • 生成逻辑:

    • 使用 JsonConfigGenerator 生成 JSON 配置,写入 material_config.json。

  • 现有功能:

    • DataColumnConfig 和 AdditionalColumnConfig 的 IsShow 默认为 true,隐藏时为 false。

    • 配置驱动的 Tabs, Fields, EnumArray, 主表,动态枚举(tb_enum_info 的 load_sql)。

    • 修复:多余逗号、Unicode、迭代器、Sequence contains no matching element。

2. 目标

  • 通过 JSON 文件加载配置:

    • 将 connectionString, joins, config 写入 JSON 文件(例如 material_input.json)。

    • 程序根据指定的 JSON 文件名称(例如 material_input.json)读取配置。

  • 动态生成:

    • 根据 JSON 文件生成对应的输出文件(例如 material_config.json)。

    • 支持多个配置文件,程序通过文件名称参数决定加载哪个配置。

  • 保持功能:

    • 现有逻辑:GenerateDataColumns, GetSelectFields, 枚举处理等。

    • IsShow 默认为 true,仅在 HiddenFields, DefaultHidden, 或 IsShow: false 时为 false。

  • 简化硬编码:

    • 移除 Test 方法中的硬编码配置。

3. 解决方案

  • JSON 配置文件:

    • 定义 InputConfig 类,包含 ConnectionString, Joins, 和 GeneratorConfig。

    • 示例 material_input.json:

      json

      {
        "ConnectionString": "Server=.;Database=TestGenerate;User Id=sa;Password=MES!qazwsx;TrustServerCertificate=true",
        "Joins": [
          { "MainTable": "tb_material", "MainAlias": "a", "JoinTable": "tb_material_group", "JoinAlias": "b", "OnClause": "a.group_id = b.id" },
          // ...
        ],
        "GeneratorConfig": {
          "Id": "material",
          "Name": "物料管理",
          "EnumArray": ["1", "5", "6", "8", "9", "12", "16"],
          "Fields": [
            { "Table": "a", "Field": "number", "Header": "物料编码", "FieldType": 0, "DataType": 0 },
            // ...
          ],
          "MainTable": "tb_material",
          "MainAlias": "a",
          "RequiredFields": ["number", "name", "model", "group_id", "unit_id"],
          "HiddenFields": ["name"],
          "Tabs": [
            { "DisplayName": "基本信息", "GroupKey": ["number", "model", "name", "disabledId", "unitId", "shelfLife", "enableShelfLife", "shelfLifeUnit", "groupId"] },
            // ...
          ],
          "EnumFields": {
            "disabled_id": 1,
            "shelf_life_unit": 5,
            // ...
          },
          "AdditionalColumns": [
            { "TableName": "tb_material_group", "TableAlias": "b", "FieldName": "group_name", "Alias": "groupName" },
            { "TableName": "tb_unit", "TableAlias": "c", "FieldName": "name", "Alias": "unitName", "IsShow": false },
            // ...
          ]
        }
      }
  • 修改程序:

    • 新增 Test 方法,接受 JSON 文件路径参数。

    • 读取 JSON 文件,反序列化为 InputConfig。

    • 使用 JsonConfigGenerator 生成输出 JSON。

  • 输出文件:

    • 根据输入文件名生成输出文件名(例如,material_input.json 生成 material_config.json)。

  • 保持现有代码:

    • JsonConfigGenerator 和相关记录类型(DataColumnConfig, AdditionalColumnConfig 等)不变。


优化后的代码

以下是修改后的代码,包含从 JSON 文件加载配置的逻辑。JsonConfigGenerator 和相关记录类型保持不变,仅更新 Test 方法和添加 InputConfig 类。

csharp

using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Threading.Tasks;

// 配置记录类型(保持不变)
public record JoinConfig(string MainTable, string MainAlias, string JoinTable, string JoinAlias, string OnClause);
public record TableField
{
    public string Name { get; init; }
    public string SqlType { get; init; }
    public string Description { get; init; }
    public bool IsEnum { get; init; }
    public int FieldType { get; init; }
    public int DataType { get; init; }
    public Dictionary<string, string>? EnumValues { get; set; }
}
public record TableConfig(string Name, string Alias, List<TableField> Fields);
public record JsonConfig(
    string Id,
    string Name,
    string Sql,
    string SqlStatistics,
    string Orderby,
    List<string> EnumArray,
    List<FieldConfig> Fields,
    List<FieldConfig> AdvancedFilterFields,
    List<DataColumnConfig> DataColumns,
    List<TabConfig> Tabs);
public record FieldConfig(string Table, string Field, string Header, int FieldType, int DataType);
public record DataColumnConfig(
    string Table,
    string Field,
    string Header,
    int FieldType,
    int DataType,
    bool Require,
    bool DefaultHidden,
    bool Disabled,
    bool IsShow = true,
    Dictionary<string, object> ExtraInfo = null) : FieldConfig(Table, Field, Header, FieldType, DataType)
{
    public DataColumnConfig(
        string Table,
        string Field,
        string Header,
        int FieldType,
        int DataType,
        bool Require,
        bool DefaultHidden,
        bool Disabled,
        bool? IsShow,
        Dictionary<string, object> ExtraInfo)
        : this(Table, Field, Header, FieldType, DataType, Require, DefaultHidden, Disabled, IsShow ?? true, ExtraInfo ?? new())
    {
    }
}
public record TabConfig(string DisplayName, List<string> GroupKey);
public record AdditionalColumnConfig(
    string TableName,
    string TableAlias,
    string FieldName,
    string Alias,
    bool Require = true,
    bool DefaultHidden = false,
    bool Disabled = false,
    bool IsShow = true
);

// 配置类
public class GeneratorConfig
{
    public string Id { get; init; } = "material";
    public string Name { get; init; } = "物料管理";
    public List<string> EnumArray { get; init; } = [];
    public List<FieldConfig> Fields { get; init; } = [];
    public string MainTable { get; init; } = "";
    public string MainAlias { get; init; } = "";
    public HashSet<string> RequiredFields { get; init; } = [];
    public HashSet<string> HiddenFields { get; init; } = [];
    public List<TabConfig> Tabs { get; init; } = [];
    public Dictionary<string, int> EnumFields { get; init; } = new();
    public List<AdditionalColumnConfig> AdditionalColumns { get; init; } = [];
}

// 输入配置类(新增)
public class InputConfig
{
    public string ConnectionString { get; init; } = "";
    public List<JoinConfig> Joins { get; init; } = [];
    public GeneratorConfig GeneratorConfig { get; init; } = new();
}

// JsonConfigGenerator(保持不变)
public class JsonConfigGenerator
{
    private readonly string _connectionString;
    private readonly List<JoinConfig> _joins;
    private readonly GeneratorConfig _config;
    private List<TableConfig> _tables = [];
    private Dictionary<int, Dictionary<string, string>> _enumValuesCache = new();

    public JsonConfigGenerator(string connectionString, List<JoinConfig> joins, GeneratorConfig config = null)
    {
        _connectionString = connectionString;
        _joins = joins;
        _config = config ?? new GeneratorConfig();
    }

    public async Task<string> GenerateAsync()
    {
        _tables = await LoadTablesAsync();
        await LoadEnumValuesAsync();
        var config = new JsonConfig(
            Id: _config.Id,
            Name: _config.Name,
            Sql: GenerateSql(),
            SqlStatistics: GenerateSqlStatistics(),
            Orderby: "a.last_modify_date DESC",
            EnumArray: _config.EnumArray,
            Fields: _config.Fields,
            AdvancedFilterFields: GenerateAdvancedFilterFields(),
            DataColumns: GenerateDataColumns(),
            Tabs: _config.Tabs
        );
        var options = new JsonSerializerOptions
        {
            WriteIndented = true,
            Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
        };
        return JsonSerializer.Serialize(config, options);
    }

    private async Task<List<TableConfig>> LoadTablesAsync()
    {
        var tables = new List<TableConfig>();
        var tableNames = _joins.Select(j => j.MainTable).Concat(_joins.Select(j => j.JoinTable)).Distinct();

        using var connection = new SqlConnection(_connectionString);
        await connection.OpenAsync();

        foreach (var tableName in tableNames)
        {
            var (schema, name) = tableName.Contains(".") ? (tableName.Split('.')[0], tableName.Split('.').Last()) : ("dbo", tableName);
            var alias = _joins.FirstOrDefault(j => j.JoinTable == tableName)?.JoinAlias ?? _joins.FirstOrDefault(j => j.MainTable == tableName)?.MainAlias ?? "a";

            var fields = new List<TableField>();
            var query = @"
                SELECT 
                    c.COLUMN_NAME AS Name,
                    c.DATA_TYPE + CASE 
                        WHEN c.DATA_TYPE IN ('nvarchar', 'varchar', 'char', 'nchar') 
                        THEN '(' + ISNULL(CAST(c.CHARACTER_MAXIMUM_LENGTH AS NVARCHAR), 'MAX') + ')'
                        ELSE '' END AS SqlType,
                    ISNULL(CAST(p.value AS NVARCHAR), c.COLUMN_NAME) AS Description
                FROM INFORMATION_SCHEMA.COLUMNS c
                LEFT JOIN sys.extended_properties p ON p.major_id = OBJECT_ID(@schema + '.' + @name) 
                    AND p.minor_id = COLUMNPROPERTY(OBJECT_ID(@schema + '.' + @name), c.COLUMN_NAME, 'ColumnId')
                    AND p.name = 'MS_Description'
                WHERE c.TABLE_SCHEMA = @schema AND c.TABLE_NAME = @name";

            using var command = new SqlCommand(query, connection);
            command.Parameters.AddWithValue("@schema", schema);
            command.Parameters.AddWithValue("@name", name);

            using var reader = await command.ExecuteReaderAsync();
            while (await reader.ReadAsync())
            {
                var fieldName = reader.GetString(0);
                var sqlType = reader.GetString(1);
                var description = reader.GetString(2);
                var isEnum = sqlType.StartsWith("tinyint", StringComparison.OrdinalIgnoreCase) || fieldName.EndsWith("_id", StringComparison.OrdinalIgnoreCase);
                var fieldType = isEnum ? 3 : sqlType.StartsWith("datetime", StringComparison.OrdinalIgnoreCase) ? 2 : 0;
                var dataType = _config.EnumFields.TryGetValue(fieldName, out var enumId) ? enumId : (isEnum ? 0 : 0);

                var enumValues = isEnum && _config.EnumFields.ContainsKey(fieldName) && _enumValuesCache.TryGetValue(dataType, out var values)
                    ? values
                    : null;

                var field = new TableField
                {
                    Name = fieldName,
                    SqlType = sqlType,
                    Description = description,
                    IsEnum = isEnum,
                    FieldType = fieldType,
                    DataType = dataType,
                    EnumValues = enumValues
                };

                fields.Add(field);
            }

            if (fields.Any())
                tables.Add(new(tableName, alias, fields));
        }

        return tables;
    }

    private async Task LoadEnumValuesAsync()
    {
        using var connection = new SqlConnection(_connectionString);
        await connection.OpenAsync();

        foreach (var (fieldName, enumId) in _config.EnumFields)
        {
            var query = "SELECT load_sql FROM tb_enum_info WHERE id = @id";
            using var command = new SqlCommand(query, connection);
            command.Parameters.AddWithValue("@id", enumId);

            var loadSql = await command.ExecuteScalarAsync() as string;
            if (string.IsNullOrEmpty(loadSql))
            {
                Console.WriteLine($"Warning: No load_sql found for enumId {enumId} ({fieldName}).");
                _enumValuesCache[enumId] = new() { ["0"] = "未知" };
                continue;
            }

            try
            {
                using var enumCommand = new SqlCommand(loadSql, connection);
                using var reader = await enumCommand.ExecuteReaderAsync();
                var values = new Dictionary<string, string>();
                while (await reader.ReadAsync())
                {
                    var id = reader.GetValue(0)?.ToString();
                    var name = reader.GetString(1);
                    if (id != null)
                        values[id] = name;
                }
                _enumValuesCache[enumId] = values.Any() ? values : new() { ["0"] = "未知" };
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error executing load_sql for enumId {enumId} ({fieldName}): {ex.Message}");
                _enumValuesCache[enumId] = new() { ["0"] = "未知" };
            }
        }
    }

    private string GetFieldDescription(string tableName, string fieldName)
    {
        var table = _tables.FirstOrDefault(t => t.Name == tableName);
        if (table == null)
        {
            Console.WriteLine($"Warning: Table '{tableName}' not found.");
            return fieldName;
        }
        var field = table.Fields.FirstOrDefault(f => f.Name == fieldName);
        if (field == null)
        {
            Console.WriteLine($"Warning: Field '{fieldName}' not found in table '{tableName}'.");
            return fieldName;
        }
        return field.Description;
    }

    private string GenerateSql() =>
        $"SELECT {string.Join(", ", GetSelectFields())} FROM {_config.MainTable} {_config.MainAlias} {string.Join(" ", _joins.Select(j => $"LEFT JOIN {j.JoinTable} {j.JoinAlias} ON {j.OnClause}"))} WHERE 1=1 {{@condition}}";

    private IEnumerable<string> GetSelectFields()
    {
        var main = _tables.FirstOrDefault(t => t.Name == _config.MainTable);
        if (main == null)
        {
            Console.WriteLine($"Warning: Table '{_config.MainTable}' not found.");
            yield break;
        }

        foreach (var f in main.Fields)
        {
            var alias = f.Name is "create_date" ? "createDate" : f.Name is "last_modify_date" ? "lastModifyDate" : f.Name;
            if (f.IsEnum)
            {
                yield return $"CAST(a.{f.Name} AS NVARCHAR(100)) AS {f.Name}";
                if (f.EnumValues != null && f.EnumValues.Any() && _config.EnumFields.ContainsKey(f.Name))
                {
                    var caseWhen = $"CASE {string.Join(" ", f.EnumValues.Select(kv => $"WHEN a.{f.Name} = {kv.Key} THEN N'{kv.Value}'"))} END AS {f.Name}Name";
                    yield return caseWhen;
                }
            }
            else
            {
                yield return $"a.{f.Name} AS {alias}";
            }
        }

        foreach (var col in _config.AdditionalColumns)
        {
            yield return $"{col.TableAlias}.{col.FieldName} AS {col.Alias}";
        }
    }

    private string GenerateSqlStatistics() =>
        $"SELECT COUNT(0) AS total FROM {_config.MainTable} {_config.MainAlias} {string.Join(" ", _joins.Select(j => $"LEFT JOIN {j.JoinTable} {j.JoinAlias} ON {j.OnClause}"))} WHERE 1=1 {{@condition}}";

    private List<FieldConfig> GenerateAdvancedFilterFields()
    {
        var main = _tables.FirstOrDefault(t => t.Name == _config.MainTable);
        return main?.Fields.Select(f => new FieldConfig("a", f.Name, f.Description, f.FieldType, f.DataType)).ToList() ?? [];
    }

    private List<DataColumnConfig> GenerateDataColumns()
    {
        var columns = new List<DataColumnConfig>();
        var main = _tables.FirstOrDefault(t => t.Name == _config.MainTable);
        if (main == null) return columns;

        foreach (var f in main.Fields)
        {
            var alias = f.Name is "create_date" ? "createDate" : f.Name is "last_modify_date" ? "lastModifyDate" : f.Name;
            var isRequired = _config.RequiredFields.Contains(f.Name);
            var isHidden = _config.HiddenFields.Contains(f.Name);
            columns.Add(new("a", alias, f.Description, f.FieldType, f.DataType, isRequired, isHidden, isHidden, !isHidden && !f.IsEnum, new()));

            if (f.IsEnum && f.EnumValues != null && _config.EnumFields.ContainsKey(f.Name))
            {
                columns.Add(new("a", $"{f.Name}Name", f.Description, 0, 0, isRequired, false, false, true, new()));
            }
        }

        columns.AddRange(_config.AdditionalColumns.Select(col =>
            new DataColumnConfig(
                col.TableAlias,
                col.Alias,
                GetFieldDescription(col.TableName, col.FieldName) ?? col.FieldName,
                0,
                0,
                col.Require,
                col.DefaultHidden,
                col.Disabled,
                col.IsShow && !col.DefaultHidden,
                new()
            )));

        return columns;
    }
}

// 测试方法
public class Program
{
    public static async Task Test(string inputJsonFile)
    {
        try
        {
            // 读取 JSON 配置文件
            if (!File.Exists(inputJsonFile))
            {
                Console.WriteLine($"Error: Input JSON file '{inputJsonFile}' not found.");
                return;
            }

            var jsonContent = await File.ReadAllTextAsync(inputJsonFile);
            var inputConfig = JsonSerializer.Deserialize<InputConfig>(jsonContent, new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true // 支持大小写不敏感
            });

            if (inputConfig == null)
            {
                Console.WriteLine("Error: Failed to deserialize input JSON.");
                return;
            }

            // 创建 JsonConfigGenerator
            var generator = new JsonConfigGenerator(
                inputConfig.ConnectionString,
                inputConfig.Joins,
                inputConfig.GeneratorConfig
            );

            // 生成 JSON 配置
            var json = await generator.GenerateAsync();

            // 生成输出文件名(基于输入文件名)
            var outputFileName = Path.GetFileNameWithoutExtension(inputJsonFile).Replace("_input", "") + "_config.json";
            await File.WriteAllTextAsync(outputFileName, json);
            Console.WriteLine($"JSON config generated: {outputFileName}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
    }

    public static async Task Main()
    {
        // 示例:传入 JSON 文件路径
        await Test("material_input.json");
    }
}

关键修改

1. InputConfig 类

  • 定义:

    csharp

    public class InputConfig
    {
        public string ConnectionString { get; init; } = "";
        public List<JoinConfig> Joins { get; init; } = [];
        public GeneratorConfig GeneratorConfig { get; init; } = new();
    }
  • 作用:

    • 封装 ConnectionString, Joins, 和 GeneratorConfig,对应原 Test 方法中的硬编码。

2. Test 方法

  • 修改:

    • 接受 inputJsonFile 参数:

      csharp

      public static async Task Test(string inputJsonFile)
    • 读取 JSON 文件:

      csharp

      var jsonContent = await File.ReadAllTextAsync(inputJsonFile);
      var inputConfig = JsonSerializer.Deserialize<InputConfig>(jsonContent, new JsonSerializerOptions
      {
          PropertyNameCaseInsensitive = true
      });
    • 动态生成输出文件名:

      csharp

      var outputFileName = Path.GetFileNameWithoutExtension(inputJsonFile).Replace("_input", "") + "_config.json";
  • 错误处理:

    • 检查文件存在性:

      csharp

      if (!File.Exists(inputJsonFile))
      {
          Console.WriteLine($"Error: Input JSON file '{inputJsonFile}' not found.");
          return;
      }
    • 处理反序列化失败:

      csharp

      if (inputConfig == null)
      {
          Console.WriteLine("Error: Failed to deserialize input JSON.");
          return;
      }

3. JSON 配置文件

  • 示例 material_input.json:

    json

    {
      "ConnectionString": "Server=.;Database=TestGenerate;User Id=sa;Password=MES!qazwsx;TrustServerCertificate=true",
      "Joins": [
        {
          "MainTable": "tb_material",
          "MainAlias": "a",
          "JoinTable": "tb_material_group",
          "JoinAlias": "b",
          "OnClause": "a.group_id = b.id"
        },
        {
          "MainTable": "tb_material",
          "MainAlias": "a",
          "JoinTable": "tb_unit",
          "JoinAlias": "c",
          "OnClause": "a.unit_id = c.id"
        },
        {
          "MainTable": "tb_material",
          "MainAlias": "a",
          "JoinTable": "tb_factory",
          "JoinAlias": "d",
          "OnClause": "d.id = a.factory_id"
        },
        {
          "MainTable": "tb_material",
          "MainAlias": "a",
          "JoinTable": "WMSIdentityServer.dbo.AbpUsers",
          "JoinAlias": "e",
          "OnClause": "e.fid = a.creator_id"
        },
        {
          "MainTable": "tb_material",
          "MainAlias": "a",
          "JoinTable": "WMSIdentityServer.dbo.AbpUsers",
          "JoinAlias": "f",
          "OnClause": "f.fid = a.last_modifier_id"
        }
      ],
      "GeneratorConfig": {
        "Id": "material",
        "Name": "物料管理",
        "EnumArray": ["1", "5", "6", "8", "9", "12", "16"],
        "Fields": [
          { "Table": "a", "Field": "number", "Header": "物料编码", "FieldType": 0, "DataType": 0 },
          { "Table": "a", "Field": "name", "Header": "物料名称", "FieldType": 0, "DataType": 0 },
          { "Table": "a", "Field": "model", "Header": "规格型号", "FieldType": 0, "DataType": 0 }
        ],
        "MainTable": "tb_material",
        "MainAlias": "a",
        "RequiredFields": ["number", "name", "model", "group_id", "unit_id"],
        "HiddenFields": ["name"],
        "Tabs": [
          {
            "DisplayName": "基本信息",
            "GroupKey": ["number", "model", "name", "disabledId", "unitId", "shelfLife", "enableShelfLife", "shelfLifeUnit", "groupId"]
          },
          {
            "DisplayName": "其它",
            "GroupKey": ["creator", "createDate", "last_modifier", "lastModifyDate"]
          }
        ],
        "EnumFields": {
          "disabled_id": 1,
          "shelf_life_unit": 5,
          "enable_shelf_life": 6,
          "unit_id": 8,
          "group_id": 9,
          "factory_id": 12,
          "creator_id": 16,
          "last_modifier_id": 16
        },
        "AdditionalColumns": [
          { "TableName": "tb_material_group", "TableAlias": "b", "FieldName": "group_name", "Alias": "groupName" },
          { "TableName": "tb_unit", "TableAlias": "c", "FieldName": "name", "Alias": "unitName", "IsShow": false },
          { "TableName": "WMSIdentityServer.dbo.AbpUsers", "TableAlias": "e", "FieldName": "UserName", "Alias": "creator" },
          { "TableName": "WMSIdentityServer.dbo.AbpUsers", "TableAlias": "f", "FieldName": "UserName", "Alias": "last_modifier" }
        ]
      }
    }

4. 未修改部分

  • JsonConfigGenerator:

    • 保持原有逻辑,包括 GenerateDataColumns, GetSelectFields, 枚举处理等。

    • IsShow 逻辑:

      • 主表字段:!isHidden && !f.IsEnum(非隐藏非枚举为 true)。

      • 枚举名称字段:true。

      • 附加列:col.IsShow && !col.DefaultHidden。

  • 其他功能:

    • 动态枚举:tb_enum_info 的 load_sql。

    • 修复:多余逗号、Unicode、迭代器、Sequence contains no matching element。


使用方法

  1. 创建 JSON 配置文件:

    • 创建 material_input.json,内容如上。

    • 放置在项目目录或指定路径。

  2. 安装 NuGet 包:

    bash

    dotnet add package System.Data.SqlClient --version 4.8.5
    dotnet add package System.Text.Json --version 8.0.0
  3. 配置数据库:

    • 确保连接字符串有效:

      json

      "ConnectionString": "Server=.;Database=TestGenerate;User Id=sa;Password=MES!qazwsx;TrustServerCertificate=true"
    • tb_enum_info 和枚举表:

      sql

      CREATE TABLE tb_enum_info (
          id INT PRIMARY KEY,
          name NVARCHAR(100),
          load_sql NVARCHAR(MAX)
      );
      INSERT INTO tb_enum_info (id, name, load_sql) VALUES
      (1, 'disabled_id', 'SELECT id, name FROM tb_disabled_status'),
      (5, 'shelf_life_unit', 'SELECT id, name FROM tb_shelf_life_units'),
      (6, 'enable_shelf_life', 'SELECT id, name FROM tb_enable_shelf_life'),
      (8, 'unit_id', 'SELECT id, name FROM tb_units'),
      (9, 'group_id', 'SELECT id, name FROM tb_material_groups'),
      (12, 'factory_id', 'SELECT id, name FROM tb_factories'),
      (16, 'creator_id', 'SELECT fid, UserName FROM WMSIdentityServer.dbo.AbpUsers');
      
      CREATE TABLE tb_shelf_life_units (
          id INT PRIMARY KEY,
          name NVARCHAR(50)
      );
      INSERT INTO tb_shelf_life_units (id, name) VALUES
      (1, '无'), (2, '日'), (3, '月'), (4, '年');
    • MS_Description:

      sql

      EXEC sys.sp_addextendedproperty 
          @name=N'MS_Description', 
          @value=N'物料编码', 
          @level0type=N'SCHEMA', @level0name=N'dbo', 
          @level1type=N'TABLE', @level1name=N'tb_material', 
          @level2type=N'COLUMN', @level2name=N'number';
  4. 运行:

    • 执行程序,指定 JSON 文件:

      bash

      dotnet run
    • 或在代码中调用:

      csharp

      await Program.Test("material_input.json");
  5. 验证输出:

    • 检查生成的 material_config.json:

      • DataColumns 中 IsShow 默认为 true,例如:

        json

        { "Table": "a", "Field": "number", "Header": "物料编码", "FieldType": 0, "DataType": 0, "Require": true, "DefaultHidden": false, "Disabled": false, "IsShow": true, "ExtraInfo": {} },
        { "Table": "a", "Field": "name", "Header": "物料名称", "FieldType": 0, "DataType": 0, "Require": true, "DefaultHidden": true, "Disabled": true, "IsShow": false, "ExtraInfo": {} },
        { "Table": "b", "Field": "groupName", "Header": "分组名称", "FieldType": 0, "DataType": 0, "Require": true, "DefaultHidden": false, "Disabled": false, "IsShow": true, "ExtraInfo": {} },
        { "Table": "c", "Field": "unitName", "Header": "单位名称", "FieldType": 0, "DataType": 0, "Require": true, "DefaultHidden": false, "Disabled": false, "IsShow": false, "ExtraInfo": {} }
      • Sql 包含附加列:

        sql

        b.group_name AS groupName, c.name AS unitName, e.UserName AS creator, f.UserName AS last_modifier
  6. 支持多配置文件:

    • 创建其他配置文件(如 product_input.json),调整 Id, MainTable 等。

    • 调用:

      csharp

      await Program.Test("product_input.json"); // 生成 product_config.json
  7. ABP 集成:

    • 使用生成的 JSON:

      csharp

      public async Task<PagedResultDto<MaterialDto>> GetPagedAsync(MaterialQueryInput input)
      {
          var config = JsonSerializer.Deserialize<JsonConfig>(File.ReadAllText("material_config.json"));
          using var connection = new SqlConnection("...");
          var query = config.Sql.Replace("{@condition}", BuildCondition(input));
          return await query.ToPagedResultAsync(input);
      }

注意事项

  1. JSON 文件格式:

    • 确保 material_input.json 格式正确,字段名匹配 InputConfig 属性。

    • 使用 PropertyNameCaseInsensitive = true 支持大小写不敏感。

  2. 文件路径:

    • 默认在项目目录查找 material_input.json。

    • 可指定绝对路径:

      csharp

      await Program.Test("C:/Configs/material_input.json");
  3. 输出文件名:

    • 自动从输入文件名生成(如 material_input.json -> material_config.json)。

    • 可自定义逻辑,例如:

      csharp

      var outputFileName = _config.Id + "_config.json"; // 使用 Id 生成
  4. 数据库:

    • 验证连接字符串和表结构:

      sql

      SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME IN ('tb_material', 'tb_material_group', 'tb_unit', 'tb_factory', 'tb_enum_info');
      SELECT * FROM tb_enum_info;
  5. 调试:

    • 检查警告:

      Warning: Table 'tb_material' not found.
      Warning,No load_sql found for enumId 5.
    • 确保 tb_enum_info 包含 id 1, 5, 6, 8, 9, 12, 16。

  6. 扩展:

    • 支持批量处理多个 JSON 文件:

      csharp

      var files = Directory.GetFiles("Configs", "*_input.json");
      foreach (var file in files)
      {
          await Program.Test(file);
      }

总结

  • 修改:

    • 新增 InputConfig 类,封装 ConnectionString, Joins, GeneratorConfig。

    • Test 方法从 JSON 文件(如 material_input.json)读取配置,生成 material_config.json。

    • 移除硬编码,程序根据输入文件路径动态生成。

  • 保留功能:

    • IsShow 默认为 true,仅在 HiddenFields, DefaultHidden, 或 IsShow: false 时为 false。

    • 配置驱动:Tabs, Fields, EnumArray, 主表,AdditionalColumns。

    • 动态枚举:tb_enum_info 的 load_sql。

    • 修复:多余逗号、Unicode、迭代器、Sequence contains no matching element。

  • JSON 输出:

    • 与原 Test 方法一致,DataColumns 和 Sql 包含配置的字段。

下一步:

  • 提供其他 JSON 配置文件(如 product_input.json)进行测试。

  • 指定是否需要自定义输出文件名逻辑。

  • 确认数据库表结构和 tb_enum_info 数据。

请提供细节(如其他配置文件或要求),我可以进一步优化!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhxup606

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值