我正在使用以下数据库设计,并希望了解我们如何在Yii中最好地解决它。
+---------------+----------------+---------------------+
| Table | Column name | Column Type |
+---------------+----------------+---------------------+
| question | id | int |
| | description | text |
| | type | ENUM('mcq', 'text') |
| | | |
| | | |
| mcq_question | id | int |
| | question_id | int |
| | option1 | text |
| | option2 | text |
| | option3 | text |
| | option4 | text |
| | correct_answer | option1 |
| | | |
| | | |
| text_question | id | int |
| | question_id | int |
| | answer | text |
+---------------+----------------+---------------------+
这个想法是有不同类型的问题,如mcq,text,grid,true / false等。他们的常见数据可以在"问题"表,而具体可以在相应的表中捕获。在简单的编程概念中,很容易将这个结构映射到问题" class,它是所有其他类的基类,如" MCQ_Question"," Text_Question"这些问题的类型将来可能会增加,因此需要灵活性。
通过上述方法,我可以使用" question_id"对于与其他表的任何外键关系,而不是使用每个单独的表,这将使代码更复杂。
从我通过阅读一些文章的理解,这种方法不适用于Yii: http://www.yiiframework.com/forum/index.php/topic/23405-cactiverecord-inheritance-and-dynamic-attributes/
Yii没办法做到吗?如果没有,那么这个问题的一些解决方法可能会使代码变得简单。
此致 卡皮尔
答案 0 :(得分:1)
您引用的链接不适用于您的问题。您可以创建派生类并覆盖tableName()
- 函数,以便它们加载出正确的表。
首先,在这种情况下,我不会为派生类型使用不同的ID,只需使用相同的ID。一个问题_所有人都更容易维护(并存储答案)。只需从派生表id字段中删除auto_increment,然后删除question_id即可。假设你这样做:
MCQ_Question的最小化示例:
class MCQ_Question extends Question
{
public $description = '';
public $type = 'mcq';
function tableName()
{
return 'mcq_question';
}
}
现在只剩下2个问题了: 1)基类中用于加载特定问题的泛型函数 2)如果保存派生类,它还应该更新/创建问题实例
1)这很简单,但您可能需要添加一个数组来转换"转换"枚举和类名之间:
class Question extends CActiveRecord
{
public function findById($questionId)
{
$types = array('mcq' => 'MCQ_Question');
$question = $this->findByPk($questionId);
if ($question && array_key_exists($question->type, $types)
{
$class = $types[$question->type];
return $class::model()->findByPk($question->id);
}
}
}
带链接的数组不是最优雅的解决方案,但它可以解决问题。您也可以将其添加为静态,以便更清楚它必须更新,等等。
2)您可以通过覆盖派生类中的beforeSave()
- 函数来完成此任务。
public function beforeSave()
{
if ($this->isNewRecord)
{
$question = new Question();
$question->type = $this->type;
$question->description = $this->description;
$question->save();
$this->id = $question->id;
}
// else check if perhaps the description was changed and update it
...
这显然不是你需要的所有代码,但是再次,你的工作不是我的工作;)
它应该让你开始。 beforeSave可能在各处几乎都是一样的,所以如果你的PHP足够新,你可以在trait
中完成。