从Yii2中的数据库多态查找模型 [英] Polymorphically find model from database in Yii2
问题描述
我在数据库中有一个表(mysql)。但是这个表存储几种略有不同类型的行。类型取决于此表的类型
列。我有一个抽象的ActiveRecord类的表和几个子类的子类实现略有不同的逻辑为不同类型的同一表的行。现在我正在为所有类型的行实现更新控制器操作。我提供了一个行的id,并需要创建一个ActiveRecord实例,表示具有此id的行。但是我不知何故需要根据相应行的类型创建不同子类的实例。
I have one table in the database(mysql). But this table stores several slightly different types of rows. The type depends on this tables's type
column. I have an abstract ActiveRecord class for a table and several descendant subclasses implementing slightly different logic for the rows of the same table of different types. Now I am implementing an update controller action for all the types of rows. I am provided with an id of the row and need to create an ActiveRecord instance representing the row with this id. But I somehow need to create instances of different subclasses depending on the type of the corresponding row.
如果我提供了一个类型和一个id,我可以使用一个工厂选择一个相应的子类。但我已经可以在数据库中的类型,一个id给我足够的信息,从那里选择。但是如果我先从数据库中选择类型,然后创建一个相应的子类的实例,这意味着执行同一个查询两次。
If I were provided with both a type and an id I could've used a factory to pick a corresponding subclass. But I can already have the type in the database and an id gives me enough information to pick it from there. But if I were to pick the type from the database first and then to create an instance of the corresponding subclass that would've meant executing the same query twice.
找到一个好的方法从数据库获取数据,然后选择一个正确的ActiveRecord子类为其创建一个实例,而不需要过多的查询或需要过多的数据。有没有办法做Yii2?
I want to find a good way to get the data from the database and then pick a right ActiveRecord subclass to create an instance for it without making excessive queries or requiring excessive data. Is there a way to do it Yii2?
或者我应该以不同的方式处理这个问题吗?实际的问题是几个几乎相同但有点不同的实体存储在具有不同的业务逻辑的单个表中。
Or should I approach this problem somehow differently? The actual problem is having several almost the same but a bit different entities stored in a single table with a bit different business-logic.
推荐答案
p>此问题的一种方法称为单表继承,由Martin Fowler描述此处 。在Yii 2中的 samdark (主要Yii 2贡献者之一)cookbook中也有一个很好的文章,它目前正在编写,但可在 Github 。
One of approaches to this problem is called "Single table inheritance" and described by Martin Fowler here. There is also good article about its implementation in Yii 2 in samdark's (one of the main Yii 2 contributors) cookbook, which is currently in process of writing but is available on Github.
我不会复制整篇文章,但留下链接也不够。以下是一些重要的事情:
I'm not going to copy the whole article, but leaving just link is also not enough. Here are some important things:
1)为所有类型的物件(例如汽车)建立通用查询:
1) Create common query for all types of objects (for example cars):
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)每种类型的模型(从常用模型汽车扩展):
2) Create separate model for each type (extending from common model 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
模型中的code> instantiate()方法返回正确类型的汽车:
3) Override instantiate()
method in Car
model to return correct type of cars:
public static function instantiate($row)
{
switch ($row['type']) {
case SportCar::TYPE:
return new SportCar();
case HeavyCar::TYPE:
return new HeavyCar();
default:
return new self;
}
}
然后你可以使用任何类型的汽车模型。
Then you can use any type of cars individually as regular models.
这篇关于从Yii2中的数据库多态查找模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!