mysql - 如何使用 Laravel 的 Eloquent 实现单表继承?

标签 mysql inheritance laravel eloquent subclass

目前我有一个名为 Post 的模型类。

class Post extends Eloquent {

    protected $table = 'posts';
    protected $fillable = array('user_id', 'title', 'description', 'views');

    /*
     * Relationships
     */

    public function user()
    {
        return $this->belongsTo('User');
    }

    public function tags()
    {
        return $this->belongsToMany('Tag', 'post_tags');
    }

    public function reactions()
    {
        return $this->hasMany('Reaction');
    }

    public function votes()
    {
        return $this->hasMany('PostVote');
    }

    //Scopes and functions...
}

我想将帖子分为两种不同的类型; 文章问题。我认为最好的方法是通过继承,所以 ArticleQuestion 将扩展 Post。最好的方法是什么?从哪里开始?

最佳答案

在深入研究多表 继承之前,我想先简单介绍一下单表 继承。当涉及到数据库模型的继承时,单表继承是更简单的方法。
您有多个模型绑定(bind)到同一个表和一个 type 列来区分不同的模型类。然而,您通常想要实现继承的原因是因为模型具有共享属性,但也有一些是模型独有的。
当使用单表继承时,您的表在某些时候看起来类似于:

id   shared_column   question_column   article_column   question_column2   article_column2 etc...
1    Lorem           62                NULL             test               NULL
2    Ipsum           NULL              x                NULL               true

您最终会得到很多 NULL 值,因为某些类型的模型不需要某些列。如果有大量记录,这会影响数据库的大小。

但是对于某些情况,它可能仍然是最佳解决方案。这是一个写得很好的Tutorial这展示了如何以一种非常优雅的方式在 Laravel 中实现它。

多表继承

现在让我们看看多表继承。使用这种方法,您可以将单个表拆分为多个表(好吧,我想这个名字已经说明了这一点;))我们将使用一种称为 Polymorphism 的技术。

我们上面例子中的模式看起来像这样:

posts table:

id   shared_column  postable_id  postable_type
1    Lorem          1            Question
2    Ipsum          1            Article


questions table:

id   question_column   question_column2
1    62                test


articles table:

id   article_column   article_column2
1    x                true

如果你问我的话,干净多了......

此处有趣的列是 postable_idpostable_type。类型告诉我们将在哪个表上找到模型的“其余部分”,id 指定属于它的记录的主键。请注意,列名可以是您想要的任何名称,但通常将其称为"-able"

现在让我们看一下 Eloquent 模型。

发布

class Post extends Eloquent {
    // all your existing code
    
    public function postable(){
        return $this->morphTo();
    }
}

问题/文章/所有其他可发布类型

class Question extends Post {
    public function post(){
        return $this->morphOne('Post', 'postable');
    }
}

请注意,您实际上不必从 Post 进行扩展,但如果您也有想要使用的方法,则可以。不管怎样,无论有没有它,多态关系都会起作用。

好的,这就是基本设置。以下是您可以如何使用新模型:

检索所有帖子

$posts = Post::all();

检索所有问题

$questions = Question::all();

从帖子中获取问题列

$post = Post::find(1);
$question_column2 = $post->postable->question_column2;

从问题中获取帖子属性

$question = Question::find(1);
$shared_column = $question->post->shared_column;

检查帖子的类型

$post = Post::find(1);
echo 'type: '.get_class($post->postable);
if($post->postable instanceof Question){
    // Looks like we got a question here
}

创建新问题

请耐心等待,创建模型有点复杂。如果您必须在应用程序的多个位置执行此操作,我建议您为其编写一个可重用的函数。

// create a record in the questions and posts table

$question = new Question();
$question->question_column = 'test';
$question->save();

$post = new Post();
$post->shared_column = 'New Question Post';
$post->save();

// link them together

$question->post()->save($post);

如您所见,干净的数据库是有代价的。处理您的模型会稍微复杂一些。但是,您可以将所有这些额外的逻辑(例如,创建模型所需的逻辑)放入模型类中的函数中,而不必担心太多。

此外,还有一个不错的 Tutorial对于 laravel 的多表继承也是如此。也许有帮助 ;)

关于mysql - 如何使用 Laravel 的 Eloquent 实现单表继承?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26691577/

相关文章:

mysql - InnoDB 二级索引包括值而不是指向 PK 的指针,这怎么够了?

php - MYSQL在PHP代码中设置时区

java - 这段关于继承的java代码有什么问题?

c++ - 如何从继承的父类创建 unique_ptr

php - 如何在 laravel 5.1 blade 中回显字符串和变量

php - Laravel 5 单元测试和命名空间

mysql - 是否可以从另一个 sql 脚本中的存储过程调用 sql 脚本?

java - XML 解析为 SQL 代码

inheritance - mongoid 继承问题

php - 防止 Laravel 向数据透视表添加多条记录