我在数据库(mysql)中有一张表。但是这个表存储了几种稍微不同类型的行。类型取决于此表的 type
列。我有一个表的抽象 ActiveRecord 类和几个后代子类,它们为不同类型的同一表的行实现略有不同的逻辑。现在我正在为所有类型的行实现更新 Controller 操作。我获得了行的 ID,需要创建一个 ActiveRecord 实例来表示具有此 ID 的行。但不知何故,我需要根据相应行的类型创建不同子类的实例。
如果同时提供类型和 ID,我可以使用工厂来选择相应的子类。但是我已经可以在数据库中拥有该类型,并且 id 为我提供了足够的信息以从那里选择它。但是,如果我先从数据库中选择类型,然后创建相应子类的实例,这将意味着执行相同的查询两次。
我想找到一种从数据库中获取数据的好方法,然后选择一个正确的 ActiveRecord 子类为其创建一个实例,而不需要进行过多的查询或需要过多的数据。 Yii2 有办法吗?
或者我应该以不同的方式处理这个问题吗?实际问题是将几个几乎相同但略有不同的实体存储在具有略微不同业务逻辑的单个表中。
最佳答案
解决此问题的方法之一称为“单表继承”,由 Martin Fowler 描述here . samdark(Yii 2 的主要贡献者之一)的食谱中也有一篇关于它在 Yii 2 中的实现的好文章,目前正在撰写中,但可以在 Github 上找到。 .
我不会复制整篇文章,但只留下链接也是不够的。以下是一些重要的事情:
1)为所有类型的对象(例如汽车)创建通用查询:
namespace app\models;
use yii\db\ActiveQuery;
class CarQuery extends ActiveQuery {
public $type;
public function prepare($builder)
{
if ($this->type !== null) {
$this->andWhere(['type' => $this->type]);
}
return parent::prepare($builder);
}
}
2)为每种类型创建单独的模型(从普通模型 Car 扩展):
跑车:
namespace app\models;
class SportCar extends Car
{
const TYPE = 'sport';
public static function find()
{
return new CarQuery(get_called_class(), ['type' => self::TYPE]);
}
public function beforeSave($insert)
{
$this->type = self::TYPE;
return parent::beforeSave($insert);
}
}
重型汽车:
namespace app\models;
class HeavyCar extends Car
{
const TYPE = 'heavy';
public static function find()
{
return new CarQuery(get_called_class(), ['type' => self::TYPE]);
}
public function beforeSave($insert)
{
$this->type = self::TYPE;
return parent::beforeSave($insert);
}
}
3) 覆盖 Car
模型中的 instantiate()
方法以返回正确的汽车类型:
public static function instantiate($row)
{
switch ($row['type']) {
case SportCar::TYPE:
return new SportCar();
case HeavyCar::TYPE:
return new HeavyCar();
default:
return new self;
}
}
然后您可以将任何类型的汽车单独用作常规模型。
关于php - 在 Yii2 中以多态方式从数据库中查找模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29167761/