Blazor+MySQL环境下动态公式存储与C#解析计算方案咨询
方案解答
一、MySQL公式存储最优表结构
推荐用两张表解耦公式本身、变量取数逻辑,扩展性和可维护性更高:
1. 公式主表 formulas
存储公式核心元数据
| 字段名 | 类型 | 说明 |
|---|---|---|
id | INT UNSIGNED AUTO_INCREMENT PRIMARY KEY | 主键 |
formula_name | VARCHAR(100) NOT NULL | 用户自定义的公式名称,用于前端展示 |
normalized_expression | TEXT NOT NULL | 标准化后的公式表达式,将用户输入的变量名替换为统一占位符,例如 ({meter_xyz123_kwh} - {meter_abc789_kwh}) / 2 |
raw_user_input | TEXT NOT NULL | 存储用户原始输入的公式内容,用于编辑回显 |
is_enabled | TINYINT(1) DEFAULT 1 | 后台调度任务是否启用该公式 |
create_time | DATETIME DEFAULT CURRENT_TIMESTAMP | 创建时间 |
update_time | DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
2. 公式变量映射表 formula_variables
存储公式中每个变量对应的数据源取数规则,和公式主表一对多关联
| 字段名 | 类型 | 说明 |
|---|---|---|
id | INT UNSIGNED AUTO_INCREMENT PRIMARY KEY | 主键 |
formula_id | INT UNSIGNED NOT NULL | 关联公式主表id,外键 |
placeholder | VARCHAR(50) NOT NULL | 对应标准化表达式中的占位符,例如 meter_xyz123_kwh |
display_name | VARCHAR(100) NOT NULL | 用户输入的变量显示名,例如 KWH value of meter xyz123 |
fetch_config | JSON NOT NULL | 该变量的MySQL取数规则,示例:{"table":"meter_history","column":"kwh","filter":"meter_sn = 'xyz123' AND stat_date = CURRENT_DATE"} |
二、公式解析实现方案
1. 开源NuGet包方案(推荐,开发成本低)
.NET5生态下有成熟的表达式解析库可以直接用,无需自己造轮子:
- NCalc:轻量级、文档完善,完全覆盖基础算术运算需求,支持参数注入、语法校验,示例代码如下:
// 从数据库拿到标准化公式和变量实际取值 var normalizedExp = "({meter_xyz123_kwh} - {meter_abc789_kwh}) / 2"; var exp = new NCalc.Expression(normalizedExp); // 注入从MySQL查询到的变量值 exp.Parameters["meter_xyz123_kwh"] = 125.6; exp.Parameters["meter_abc789_kwh"] = 83.2; // 计算结果,可提前调用HasErrors()方法做语法校验 var result = Convert.ToDecimal(exp.Evaluate());
- DynamicExpresso:性能略优于NCalc,语法更贴近C#原生,同样支持.NET5,适合后续需要扩展自定义函数的场景。
2. .NET5原生工具实现方案
如果不能引入第三方依赖,也可以用.NET自带的System.Linq.Expressions表达式树实现,不过需要自行开发词法解析、语法校验逻辑:
- 第一步:实现简单的词法分析器,将公式拆分为操作符、数值、变量三类Token
- 第二步:按照算术优先级(括号>乘除>加减)把Token转换为表达式树节点,变量节点绑定从MySQL查询到的实际值
- 第三步:编译表达式树为可执行委托,调用得到计算结果
该方案仅适合公式规则固定、无复杂扩展需求的场景,否则自定义解析逻辑的维护成本很高。
内容的提问来源于stack exchange,提问作者Tom Boudniatski
相关产品推荐
相关产品推荐

