Php 在Yii2中设置非规范化列的最佳实践
向所有Yii2标准化极客提问 在Yii2中设置非规范化列的最佳位置是哪里 例如,我有客户、分行、收银机和交易等型号。 在一个完美的世界中,在一个完美规范化的数据库中,交易模型将只有Php 在Yii2中设置非规范化列的最佳实践,php,mysql,yii2,database-normalization,Php,Mysql,Yii2,Database Normalization,向所有Yii2标准化极客提问 在Yii2中设置非规范化列的最佳位置是哪里 例如,我有客户、分行、收银机和交易等型号。 在一个完美的世界中,在一个完美规范化的数据库中,交易模型将只有收银机id,收银机将存储分行id,而分行将存储客户id。但是,由于性能问题,我们有时不得不使用非规范化的事务模型,其中包含以下内容: 收银机 分支机构id 客户识别码 创建事务时,我希望存储所有3个值。背景 $transaction->branch_id = $transaction->cashRegist
收银机id
,收银机将存储分行id
,而分行将存储客户id
。但是,由于性能问题,我们有时不得不使用非规范化的事务模型,其中包含以下内容:
$transaction->branch_id = $transaction->cashRegister->branch_id;
$transaction->customer_id = $transaction->cashRegister->branch->customer_id;
但是,在控制器中感觉不正确
一种解决方案是在事务模型中的aftersave()中执行此操作,并将这些列设置为只读。但这似乎更好,但并不完美
我想知道什么是设置这些重复列的最佳做法,或者在哪里设置这些重复列的最佳位置,以确保数据的完整性?我曾经遇到过类似的问题,使用
afterSave()
或beforeSave()
一开始看起来是一个很好的解决方案,但最终导致难以维护意大利面代码。我最终创建了单独的组件来管理这种关系。比如:
class TransactionsManager extends Component {
public function createTransaction(TransactionInfo $info, CashRegister $register) {
// magic
}
}
然后,您不会直接创建或更新
事务模型,而是始终使用此组件并将所有逻辑封装在其中。ActiveRecord的工作原理更像是一种数据表示,不包含任何高级业务逻辑。在某些情况下,它看起来比$model->load($data)&&&$model->save()
更复杂,但毕竟,当您将所有逻辑放在一个地方,并且不需要调试save()
调用链时,维护起来就容易多了(一个模型在运行afterSave()
的中运行不同模型的save()
)
在afterSave()
…等中的不同型号。以下是一个仅适用于DB的解决方案
我想你们的关系是:
- 客户有许多分支机构
- 分行有许多收款机
- 收银机有许多交易
相应的模式可以是:
创建表客户(
客户id int自动增量,
客户数据文本,
主键(客户id)
);
创建表分支(
分支id int自动增量,
客户id int不为空,
分支_数据文本,
主键(分支id),
索引(客户id),
外键(客户id)引用客户(客户id)
);
创建表现金出纳(
收银机id自动递增,
分支id int不为空,
收银机数据文本,
主键(收银机id),
索引(分支机构id),
外键(分支id)引用分支(分支id)
);
创建表事务(
事务id int自动增量,
收银机\u id int不为空,
事务处理单元数据文本,
主键(事务_id),
索引(收银机id),
外键(收银机id)引用收银机(收银机id)
);
(注意:这应该是你问题的一部分,所以我们不需要猜测。)
如果要在交易
表中包含冗余列(分支机构id
和客户id
),则应将它们作为外键的一部分。但首先,您需要在现金登记薄
表中包含客户id
列,并将其作为外键的一部分
扩展模式将是:
创建表客户(
客户id int自动增量,
客户数据文本,
主键(客户id)
);
创建表分支(
分支id int自动增量,
客户id int不为空,
分支_数据文本,
主键(分支id),
索引(客户id、分支机构id),
外键(客户id)引用客户(客户id)
);
创建表现金出纳(
收银机id自动递增,
分支id int不为空,
客户id int不为空,
收银机数据文本,
主键(收银机id),
索引(客户id、分行id、收银机id),
外键(客户id、分支机构id)
参考分行(客户id、分行id)
);
创建表事务(
事务id int自动增量,
收银机\u id int不为空,
分支id int不为空,
客户id int不为空,
事务处理单元数据文本,
主键(事务_id),
索引(客户id、分行id、收银机id),
外键(客户id、分行id、收银机id)
参考收银机(客户id、分行id、收银机id)
);
注:
- 任何外键约束都需要在子(引用)表和父(引用)表中建立索引,以支持约束检查。键中给定的列顺序允许我们定义每个表只有一个索引的模式
- 外键应始终引用父表中的唯一键。但是,在本例中,引用列的组合(至少)是隐式唯一的,因为它包含主键。在几乎任何其他RDBMS中,您都需要将“中间”表(
分支机构
和收银机
)中的索引定义为唯一
。然而,这在MySQL中不是必需的
- 复合外键将负责数据完整性/一致性。示例:如果您有一个分行分录,其
分行id=2
和客户id=1
-您将无法插入一个分行id=2
和客户id的收银机