数据库适配层
简介
数据库适配层是Known项目中的核心组件,负责为系统提供多种数据库支持。它通过统一的接口抽象不同数据库的差异,使上层业务代码无需关心底层数据库的具体实现。
项目结构
数据库适配层主要位于Shared/Data/
目录下,包含以下关键文件:
DbProvider.SqlServer.cs
- SQL Server数据库适配器DbProvider.MySql.cs
- MySQL数据库适配器DbProvider.SQLite.cs
- SQLite数据库适配器DbProvider.Oracle.cs
- Oracle数据库适配器
classDiagram class DbProvider{ <<abstract>> +Database db +FormatName(string name): string +FormatBoolean(bool value): object +GetBooleanSql(string field, bool isTrue): string +GetTableSql(string dbName): string +GetTableScript(string tableName, DbModelInfo info): string +GetTopSql(int size, string text): string } DbProvider <|-- SqlServerProvider DbProvider <|-- MySqlProvider DbProvider <|-- SQLiteProvider DbProvider <|-- OracleProvider
核心组件
数据库适配层的核心是DbProvider
抽象基类,它定义了所有数据库适配器必须实现的接口。各具体数据库适配器继承并实现这些接口。
1. 数据库适配器基类(DbProvider)
- 提供数据库操作的统一抽象
- 定义公共接口和默认实现
- 管理数据库连接
2. 具体数据库适配器
每种数据库都有对应的适配器实现:
SQL Server适配器
- 表名使用
[表名]
格式 - 布尔值转换为1/0
- 分页使用
TOP
语法
MySQL适配器
- 表名使用
表名
格式 - 分页使用
LIMIT
语法 - 支持表注释作为表名
SQLite适配器
- 表名使用
[表名]
格式 - 分页使用
LIMIT OFFSET
语法 - 自动主键处理
Oracle适配器
- 参数使用
:参数名
格式 - 日期格式化处理
- 使用
ALTER TABLE
添加主键
架构概述
数据库适配层采用抽象工厂模式,通过统一的DbProvider
接口屏蔽不同数据库的差异。上层代码只需与DbProvider
交互,无需关心具体数据库类型。
flowchart TD A[业务代码] --> B[DbProvider] B --> C[SqlServerProvider] B --> D[MySqlProvider] B --> E[SQLiteProvider] B --> F[OracleProvider]
详细组件分析
1. 表结构生成
所有适配器都实现了GetTableScript
方法,用于生成创建表的SQL语句。
示例(SQL Server):
internal static string GetTableScript(string tableName, List<FieldInfo> fields, List<string> keys, int maxLength = 0)
{
var sb = new StringBuilder();
sb.AppendLine("CREATE TABLE [{0}] (", tableName);
foreach (var item in fields)
{
var required = item.Required ? "NOT NULL" : "NULL";
var column = $"[{item.Id}]";
column = GetColumnName(column, maxLength + 2);
var type = GetSqlServerDbType(item);
sb.AppendLine($" {column} {type} {required},");
}
if (keys != null && keys.Count > 0)
{
var key = string.Join(", ", keys.Select(k => $"[{k}] ASC"));
sb.AppendLine($" CONSTRAINT [PK_{tableName}] PRIMARY KEY ({key})");
}
sb.AppendLine(");");
return sb.ToString();
}
2. 数据类型映射
每种适配器都实现了类型映射方法,如GetSqlServerDbType
:
private static string GetSqlServerDbType(FieldInfo item)
{
string type;
if (item.Type == FieldType.Date || item.Type == FieldType.DateTime)
type = "[datetime]";
else if (item.Type == FieldType.CheckBox || item.Type == FieldType.Switch)
type = "[int]";
else if (item.Type == FieldType.Number)
type = string.IsNullOrWhiteSpace(item.Length) ? "[int]" : $"[decimal]({item.Length})";
else
{
if (string.IsNullOrWhiteSpace(item.Length))
type = "[ntext]";
else if (item.Id.StartsWith("Is") || item.Id.EndsWith("Id") || item.Id.EndsWith("No") || item.Id == "CompNo")
type = $"[varchar]({item.Length})";
else
type = $"[nvarchar]({item.Length})";
}
if (type.Length < 16)
type += new string(' ', 16 - type.Length);
return type;
}
依赖关系分析
数据库适配层主要依赖:
Database
类 - 提供基础数据库连接功能FieldInfo
类 - 字段元数据信息DbModelInfo
类 - 表模型信息
classDiagram DbProvider --> Database DbProvider --> FieldInfo DbProvider --> DbModelInfo
性能考量
- SQL生成优化:使用
StringBuilder
构建SQL语句,避免字符串拼接性能问题 - 类型映射缓存:可以考虑缓存类型映射结果,减少重复计算
- 分页处理:各数据库分页语法不同,适配器需要针对特定数据库优化分页查询
常见问题解决
1. 如何添加新的数据库支持?
- 创建新的适配器类继承
DbProvider
- 实现所有抽象方法
- 注册到数据库工厂中
示例骨架:
class NewDbProvider : DbProvider
{
// 实现必要的方法
internal override string GetTableSql(string dbName) { ... }
internal override string GetTableScript(...) { ... }
// 其他方法实现
}
2. 连接字符串处理
MySQL适配器提供了连接字符串解析示例:
private string GetSchemaName(string dbName)
{
var items = Database.ConnectionString.Split(';');
foreach (var item in items)
{
var names = item?.Split('=');
if (names != null && names.Length > 1 &&
(names[0] == "Initial Catalog" || names[0] == "Database"))
{
dbName = names[1];
break;
}
}
return dbName;
}
3. 布尔值处理差异
不同数据库对布尔值的处理不同,适配器需要统一处理:
- SQL Server/Oracle: 转换为1/0
- MySQL/SQLite: 使用特定语法
结论
数据库适配层通过统一的接口抽象,使Known项目能够灵活支持多种数据库。各适配器封装了数据库特定的语法和特性,上层业务代码可以无缝切换不同数据库。这种设计提高了系统的可扩展性和可维护性,是典型的多态和抽象工厂模式的应用。