【问题标题】:Yii: When to use single table inheritance. Clarifying usage and understandingYii:什么时候使用单表继承。澄清用法和理解
【发布时间】:2013-07-19 13:03:42
【问题描述】:

假设我有一个在线商店,产品按整数或小数重量进行库存和销售。有不同类型的产品。并非所有项目都相关。我需要决定是否应该将它们放在单独的表中(规范化)或使用一种称为单表继承的技术,这种技术使我能够将所有产品存储在同一个表中,但对每种类型的产品使用不同的模型类。

一个简单的例子。

大米的储存量是每公斤(十进制)而不是每粒(整数)。 大米将按公斤(十进制)出售,但您不能出售 1.5 个苹果(十进制)。

这是单表继承的用途还是我错过了它的用途?

数据库示例

CREATE TABLE `product` (
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`unit` varchar(100) NOT NULL,
`stock` decimal(10,3) NOT NULL,
PRIMARY KEY (`id`)
);

INSERT INTO `product` (`name`, `unit`, `stock`)
VALUES 
('Rice', 'Kilo', 10.00),
('Apple', 'Each', 500),
('Orange', 'Each', 230),
('Flour', 'Kilo', 55.3),
('Coke', 'Litre', 123.5);

型号(为简单起见,仅显示产品和公斤单位类型)

class Product extends CActiveRecord {
    ...
        STUFF
    ...
    protected function instantiate($attributes)
    {
        switch($attributes['unit'])
        {
            case 'Kilo':
                $class='KiloUnit';
                break;
            case 'Each':
                $class='EachUnit';
                break;
            case 'Litre':
                $class='LitreUnit';
                break;
            default:
                $class=get_class($this);
        }
        $model=new $class(null);
        return $model;
    }
}

class KiloUnit extends Product {
    public static function model($className=__CLASS__)
    {
        return parent::model($className);
    }
    public function defaultScope()
    {
        return array(
            'condition'=>"type='Kilo'",
        );
    }

    public function rules(){
        array('stock', 'numerical'),
    }

    public function attributeLabels()
    {
        return array('stock' => 'Kilo');
    }

模型“EachUnit”的规则类似于

array('stock','numerical', 'integerOnly'=>true)

模型“EachUnit”的属性标签类似于

return array('stock' => 'Quantity');

这样,如果我希望使用所有产品,我可以使用以下内容:

$products = Product::model()->findAll();
foreach($products as $p)
{
   do something
}

如果我只想处理以公斤为单位类型的产品

$products = KiloUnit::model()->findAll();
foreach($products as $p)
{
   do something
}

【问题讨论】:

    标签: php yii single-table-inheritance yii-cmodel


    【解决方案1】:

    由于我对单表继承这个术语有点陌生,所以我对单表继承进行了更多研究,并认为这确实值得一个答案,而不是一堆 cmets。

    当您有一组需要持久化到数据库中的相似对象时,单表继承就会发挥作用。您可以将对象拆分为单独的表,或者如果它们足够相似,您可以将它们全部保存在一个表中,并带有一个字段来识别哪个是哪个。对象是不同的,因为它们需要不同的处理或具有稍微不同的属性。在您的情况下,我认为不同的度量单位不足以将其称为 单表继承,但更一般地说,您可以拥有按数量存储的项目和按数量存储的项目,它们都具有相同的集合属性,但不同的方法来处理库存或成本的消耗,所以我想你可以在技术上称之为单表继承。但我什至认为这还不够重要,因为处理两者的方法甚至相似。

    这里是一个项目类的例子,你可能更符合这个概念。想想制造应用程序。在这种情况下,您有一些物品,有些是购买的,有些是制造的。这些项目具有许多相同的属性,但制造的项目将具有材料清单和与制造过程有关的属性,而购买的项目将具有供应商以及与购买过程相关的属性。很可能所有这些属性都适合同一个表,有些属性对于购买的商品为空,有些对于制造的商品为空,但是使用单表继承,您可以使用单个查询搜索所有商品,或进行交易与知道他们独特品质的班级一起。在这种情况下,您可以节省一些连接时间并简化前端,因为差异更加显着,而且 SQL 联合的成本可能很高。但只是针对不同的计量单位?可能不那么值得。

    这里是 Single Table Inheritance 上 Yii 文档的链接。

    【讨论】:

    • 您好,感谢您的回答。我的想法和你的一致。我确实试图稍微简化这个问题,这就是我谈到计量单位的原因。例如,产品也将按数量或重量销售。在线系统需要动态地向用户请求他们希望购买多少,或者他们希望购买多少公斤。因此,需要对模型进行不同的处理。我可以买 1.5 公斤的糖,但我不能买 1.5 个苹果。
    • 哦,还有用于研究的 +1。 :)
    • 仍然没有代码重复。为您的数量字段创建自定义验证器。使用 UOM 确定允许的小数精度(我会使用 UOM 文件中的字段),如果存在太多小数位,则会引发错误。
    【解决方案2】:

    我可能会改变的一件事是,您可以创建一个名为measurement 的表,然后在您的产品表中存储一个measurement_id。然后,您可以将一些其他功能移至测量模型,而不是将其放在产品模型上。然后,当您创建产品时,您可以轻松创建所有 measurement 选项的下拉列表。我不知道在这种情况下一定有正确或错误的方式。

    【讨论】:

    • 我同意你的说法,但是将这些数据标准化并放在单独的表中的传统方法会在表中引入一个额外的连接,每次都需要查询该连接以确定测量/单位类型。 - 减慢数据库访问速度并使前端开发成为一场噩梦。这就是我考虑使用单表继承的原因。
    • 对于您的单位,我可能会将单位存储为枚举或映射到您想要的特定模型的整数。但总的来说,是的,这种类型的继承工作得很好。有一种不同的类型(您还希望在其中映射另一个表),这会变得非常混乱(想想子类化一个表。如果你最终去那里要小心:-)
    • @Gravy:数据库访问速度慢?噩梦般的前端开发?我认为你在那儿有点戏剧化。提供选择的下拉菜单是相当标准的票价,如果您有适当的索引,这些小连接只会为数据库访问增加微秒。您永远不会在网络流量的噪音中看到它。我认为这属于过早优化的范畴,如果它增加了应用程序的复杂性,那就不值得了。
    • 在代码复杂性和代码重复方面的噩梦。
    猜你喜欢
    • 1970-01-01
    • 2011-03-05
    • 1970-01-01
    • 2010-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-24
    • 2010-10-22
    相关资源
    最近更新 更多