我将为你提供一个基于DDD(领域驱动设计)和ABP框架的代码生成工具的设计思路和实现方案,重点处理数据库表到代码的映射,尤其是tinyint到枚举、float到double的类型转换,并支持可配置的类型映射关系。以下是详细的中文解释和实现步骤。
1. 需求分析
目标:根据数据库表结构,自动生成ABP框架的增删改查(CRUD)功能代码,符合DDD分层架构(Application、Domain、Infrastructure)。
特殊要求:
数据库中的tinyint映射为C#的枚举类型。
数据库中的float映射为C#的double类型。
类型映射关系可配置,允许用户自定义数据库类型与C#类型的对应关系。
生成内容:
Domain层:实体(Entity)、值对象(Value Object)、枚举、仓储接口(IRepository)。
Application层:应用服务接口和服务实现(AppService)、DTO。
Infrastructure层:EF Core实体配置、仓储实现。
API层:控制器(Controller)实现RESTful CRUD接口。
2. 工具设计
2.1 核心组件
表结构解析器:读取数据库表结构,获取表名、列名、数据类型等信息。
类型映射器:根据配置文件,将数据库类型(如tinyint、float)映射为C#类型(如枚举、double)。
代码生成器:基于模板(T4或字符串模板)生成各层的代码。
配置管理器:支持用户自定义类型映射规则(如JSON或XML配置文件)。
2.2 类型映射配置
创建一个可配置的类型映射文件(例如TypeMapping.json),用户可以定义数据库类型到C#类型的映射。例如:
json
{
"TypeMappings": [
{
"DatabaseType": "tinyint",
"CSharpType": "enum",
"DefaultEnumName": "{ColumnName}Enum",
"EnumValues": ["Unknown", "Value1", "Value2"] // 可动态配置
},
{
"DatabaseType": "float",
"CSharpType": "double"
},
{
"DatabaseType": "varchar",
"CSharpType": "string"
}
]
}
tinyint:映射为枚举,枚举名称基于列名生成(如Status列生成StatusEnum)。
float:映射为C#的double。
用户可通过修改配置文件添加或调整映射规则。
2.3 技术选型
语言:C#(.NET Core/ASP.NET Core)。
框架:ABP vNext(支持DDD分层)。
模板引擎:T4模板或Roslyn动态生成代码。
数据库访问:Entity Framework Core(支持表结构反射)。
配置文件:JSON或XML,存储类型映射规则。
3. 实现步骤
以下以一个示例表Users说明代码生成过程,表结构如下:
sql
CREATE TABLE Users (
Id BIGINT PRIMARY KEY,
Name VARCHAR(50),
Age INT,
Status TINYINT,
Height FLOAT
);
3.1 表结构解析
使用EF Core的IModel或直接查询数据库元数据(如INFORMATION_SCHEMA.COLUMNS)获取表结构信息。示例代码:
csharp
public class TableSchemaReader
{
private readonly DbContext _dbContext;
public TableSchemaReader(DbContext dbContext)
{
_dbContext = dbContext;
}
public List<TableSchema> GetTableSchemas()
{
var tables = new List<TableSchema>();
// 假设使用SQL Server,查询INFORMATION_SCHEMA
var sql = @"SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS";
var result = _dbContext.Database.SqlQueryRaw<ColumnInfo>(sql).ToList();
// 按表分组并转换为TableSchema
// ...
return tables;
}
}
public class TableSchema
{
public string TableName { get; set; }
public List<ColumnSchema> Columns { get; set; }
}
public class ColumnSchema
{
public string ColumnName { get; set; }
public string DataType { get; set; }
public bool IsPrimaryKey { get; set; }
}
3.2 类型映射
根据TypeMapping.json配置文件,将数据库类型转换为C#类型。示例代码:
csharp
public class TypeMapper
{
private readonly Dictionary<string, TypeMapping> _mappings;
public TypeMapper(string configFilePath)
{
var config = JsonSerializer.Deserialize<TypeMappingConfig>(File.ReadAllText(configFilePath));
_mappings = config.TypeMappings.ToDictionary(m => m.DatabaseType, m => m);
}
public string MapToCSharpType(string dbType, string columnName)
{
if (_mappings.TryGetValue(dbType.ToLower(), out var mapping))
{
if (mapping.CSharpType == "enum")
{
return mapping.DefaultEnumName.Replace("{ColumnName}", columnName);
}
return mapping.CSharpType;
}
return "string"; // 默认映射
}
}
public class TypeMappingConfig
{
public List<TypeMapping> TypeMappings { get; set; }
}
public class TypeMapping
{
public string DatabaseType { get; set; }
public string CSharpType { get; set; }
public string DefaultEnumName { get; set; }
public List<string> EnumValues { get; set; }
}
3.3 代码生成
使用T4模板或字符串模板生成各层代码。以下是主要代码片段的示例。
3.3.1 Domain层 - 实体
生成User实体,Status字段为枚举,Height为double。
csharp
public class User : AuditedAggregateRoot<long>
{
public string Name { get; set; }
public int Age { get; set; }
public StatusEnum Status { get; set; }
public double Height { get; set; }
}
public enum StatusEnum
{
Unknown = 0,
Value1 = 1,
Value2 = 2
}
T4模板(Entity.tt)示例:
tt
<#@ parameter name="Table" type="TableSchema" #>
namespace MyApp.Domain.Entities
{
public class <#= Table.TableName #> : AuditedAggregateRoot<long>
{
<# foreach (var column in Table.Columns) { #>
public <#= TypeMapper.MapToCSharpType(column.DataType, column.ColumnName) #> <#= column.ColumnName #> { get; set; }
<# } #>
}
}
3.3.2 Domain层 - 仓储接口
生成IUserRepository:
csharp
public interface IUserRepository : IRepository<User, long>
{
Task<List<User>> GetByStatusAsync(StatusEnum status);
}
3.3.3 Application层 - DTO
生成UserDto和CreateUpdateUserDto:
csharp
public class UserDto : AuditedEntityDto<long>
{
public string Name { get; set; }
public int Age { get; set; }
public StatusEnum Status { get; set; }
public double Height { get; set; }
}
public class CreateUpdateUserDto
{
public string Name { get; set; }
public int Age { get; set; }
public StatusEnum Status { get; set; }
public double Height { get; set; }
}
3.3.4 Application层 - 应用服务
生成IUserAppService和UserAppService:
csharp
public interface IUserAppService : IApplicationService
{
Task<UserDto> GetAsync(long id);
Task<PagedResultDto<UserDto>> GetListAsync(PagedAndSortedResultRequestDto input);
Task<UserDto> CreateAsync(CreateUpdateUserDto input);
Task<UserDto> UpdateAsync(long id, CreateUpdateUserDto input);
Task DeleteAsync(long id);
}
public class UserAppService : ApplicationService, IUserAppService
{
private readonly IUserRepository _userRepository;
public UserAppService(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public async Task<UserDto> GetAsync(long id)
{
var user = await _userRepository.GetAsync(id);
return ObjectMapper.Map<User, UserDto>(user);
}
// 其他CRUD方法...
}
3.3.5 Infrastructure层 - EF Core配置
生成UserConfiguration:
csharp
public class UserConfiguration : IEntityTypeConfiguration<User>
{
public void Configure(EntityTypeBuilder<User> builder)
{
builder.ToTable("Users");
builder.HasKey(x => x.Id);
builder.Property(x => x.Name).HasMaxLength(50).IsRequired();
builder.Property(x => x.Status).HasConversion<int>();
builder.Property(x => x.Height).HasColumnType("float");
}
}
3.3.6 API层 - 控制器
生成UserController:
csharp
[Route("api/users")]
public class UserController : AbpControllerBase
{
private readonly IUserAppService _userAppService;
public UserController(IUserAppService userAppService)
{
_userAppService = userAppService;
}
[HttpGet("{id}")]
public async Task<UserDto> GetAsync(long id)
{
return await _userAppService.GetAsync(id);
}
[HttpPost]
public async Task<UserDto> CreateAsync(CreateUpdateUserDto input)
{
return await _userAppService.CreateAsync(input);
}
// 其他CRUD方法...
}
3.4 工具执行流程
读取表结构:连接数据库,获取所有表和列的元数据。
加载类型映射:读取TypeMapping.json,初始化类型映射器。
生成代码:
遍历表结构,生成Domain层的实体和枚举。
为每个实体生成仓储接口、应用服务、DTO、EF Core配置和控制器。
保存代码:将生成的代码写入指定项目目录,遵循ABP的模块化结构。
验证:可选,运行单元测试验证生成的代码。
4. 示例工具代码
以下是一个简单的工具主程序:
csharp
public class CodeGenerator
{
private readonly TableSchemaReader _schemaReader;
private readonly TypeMapper _typeMapper;
private readonly string _outputPath;
public CodeGenerator(string connectionString, string configFilePath, string outputPath)
{
_schemaReader = new TableSchemaReader(new MyDbContext(connectionString));
_typeMapper = new TypeMapper(configFilePath);
_outputPath = outputPath;
}
public void Generate()
{
var tables = _schemaReader.GetTableSchemas();
foreach (var table in tables)
{
GenerateEntity(table);
GenerateRepository(table);
GenerateAppService(table);
GenerateDto(table);
GenerateEfConfiguration(table);
GenerateController(table);
}
}
private void GenerateEntity(TableSchema table)
{
var template = new EntityTemplate(_typeMapper); // 假设使用自定义模板类
var code = template.TransformText(table);
File.WriteAllText(Path.Combine(_outputPath, $"Domain/Entities/{table.TableName}.cs"), code);
}
// 其他生成方法类似...
}
5. 使用说明
准备配置文件:创建TypeMapping.json,定义数据库类型到C#类型的映射。
运行工具:
bash
dotnet run --connectionString "Server=localhost;Database=MyDb;..." --configFile "TypeMapping.json" --outputPath "MyApp"
整合到ABP项目:
将生成的代码放入ABP项目的对应模块。
更新DbContext,添加实体配置。
运行迁移,生成数据库表。
6. 注意事项
枚举值处理:对于tinyint映射的枚举,工具需要用户在TypeMapping.json中指定可能的枚举值,或通过表注释/元数据自动推导。
性能优化:对于大型数据库,建议缓存表结构信息,避免重复查询。
扩展性:支持更多的数据库类型(如MySQL、PostgreSQL)和C#类型映射。
错误处理:添加输入验证,确保表结构和配置文件合法。
ABP版本兼容性:确保生成的代码与目标ABP版本(例如vNext 8.x)兼容。
7. 扩展功能
自定义模板:允许用户提供自己的T4模板,增加灵活性。
多语言支持:生成多语言的错误消息或UI提示。
增量生成:仅生成新增或修改的表对应的代码,避免覆盖已有代码。
集成测试:生成单元测试代码,验证CRUD功能。
8. 总结
通过上述设计,工具能够根据数据库表结构自动生成符合DDD和ABP框架的CRUD代码,处理tinyint到枚举、float到double的映射,并通过配置文件支持灵活的类型映射。用户只需提供数据库连接字符串和类型映射配置文件,即可快速生成项目代码,减少手动编码的工作量。
如果你需要更详细的某部分代码(如T4模板的具体实现)或有其他特殊需求,请告诉我!