【问题标题】:HasMany Object or Eloquent: Which is better?HasMany Object 或 Eloquent:哪个更好?
【发布时间】:2018-02-27 01:54:07
【问题描述】:

我有 blog 的以下控制器

public function show($slug)
{
    $post = Blog::where('slugs', '=', $slug)->first();

    $vars['pageTitle'] = Config::get('site.pageTitle') . $post['title'];

    // The breadcrumbs... needs to be repopulated every page
    $vars['breadCrumbs'] = [[
        'url'   => action('SimpleController@index'),
        'title' => 'CovertDEV'
    ],[
        'url'   => action('BlogController@index'),
        'title' => 'Blog'
    ],[
        'url'   => route('blog_post', ['slug' => $slug]),
        'title' => $post['title']
    ]];

    $vars['blog'] = $post;

    // The following line is what the question is about
    $vars['comments'] = $post->Blog_comments->groupBy('comment_id');

    return view('blog', $vars);
}

我的博客模型最初看起来像

namespace App;

use Illuminate\Database\Eloquent\Model;

class Blog extends Model
{
    //

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

    public function blog_comments()
    {
        return $this->hasMany('App\Blog_comment');
    }

    public function users()
    {
        return $this->belongsTo('App\User', 'user_id');
    }
}

对于 blog_cmets

namespace App;

use Illuminate\Database\Eloquent\Model;

class Blog_comment extends Model
{
    //

    public function users()
    {
        return $this->belongsTo('App\User', 'user_id');
    }

    public function blogs()
    {
        return $this->belongsTo('App\Blog');
    }

}

我正在检索帖子的 cmets 并将其显示在页面上。一切都运行良好...但后来我尝试使用我的关系代替...(将那条线更改为...)

$vars['comments'] = $post->blog_comments()->get()->groupBy('comment_id');

这同样有效。我的帖子不大,只是一个简单的“Lorem Ipsum”测试文本和 7 个 cmets 来测试该功能,所以我看不出这两种方法的加载时间有任何差异。

还是两者都一样?以前的方式看起来更好,但我不确定我是否按预期实现 ORM,如果没有,那么哪种方式更好?

但我是 Laravel 的新手(这是我的第一个框架),所以我不知道...哪种方式更好/更快/更高效?也许有一种我还不知道的更好/更有效的方法来实现这一点。

对不起,如果这看起来很明显。我想在继续项目之前解决这个问题...不想在找到将信息联系在一起的更好方法后重做所有事情。

提前致谢!

我的数据库转储是

CREATE TABLE `blog_comments` (
  `id` int(10) UNSIGNED NOT NULL,
  `user_id` int(10) UNSIGNED NOT NULL,
  `blog_id` int(10) UNSIGNED NOT NULL,
  `comment_id` int(11) NOT NULL DEFAULT '0',
  `comment` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `likes` int(11) NOT NULL DEFAULT '0',
  `deleted_at` timestamp NULL DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

--
-- Dumping data for table `blog_comments`
--

INSERT INTO `blog_comments` (`id`, `user_id`, `blog_id`, `comment_id`, `comment`, `likes`, `deleted_at`, `created_at`, `updated_at`) VALUES
(1, 1, 2, 0, 'Interesting post. Very well structured and good points throughout! One question though, Enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit?', 0, NULL, '2018-02-24 20:31:45', '2018-02-24 20:31:45'),
(2, 2, 2, 1, 'Thank you, very interesting question. Unique point of view. Semper viverra nam libero justo. Sit amet commodo nulla facilisi. Blandit massa enim nec dui nunc. Eget velit aliquet sagittis id consectetur purus ut faucibus.', 0, NULL, '2018-02-25 02:26:32', '2018-02-25 02:26:32'),
(3, 1, 2, 1, 'Indeed! I can now finally lorem ipsum by myself all the way commodo nulla facilisi!', 0, NULL, '2018-02-25 04:36:18', '2018-02-25 04:36:18'),
(4, 2, 2, 0, 'Weird, I thought I had more information posted. Must have being moderated out of existence then.', 0, NULL, '2018-02-25 09:18:58', '2018-02-25 09:18:58'),
(5, 1, 2, 4, 'Sorry about that, you had quite a few needless stuff in there. Had to tweak your post a bit. Otherwise, everything is lorem ipsum!', 0, NULL, '2018-02-25 12:53:18', '2018-02-25 12:53:18'),
(6, 2, 2, 3, 'Glad that it works for you!', 0, NULL, '2018-02-26 05:35:46', '2018-02-26 05:35:46'),
(7, 1, 2, 6, 'Thank you, feels good!', 0, NULL, '2018-02-25 07:08:33', '2018-02-25 07:08:33');

--
-- Indexes for dumped tables
--

--
-- Indexes for table `blog_comments`
--
ALTER TABLE `blog_comments`
  ADD PRIMARY KEY (`id`),
  ADD KEY `blog_comments_user_id_index` (`user_id`),
  ADD KEY `blog_comments_blog_id_index` (`blog_id`);

我需要结果数组如下所示:

Array
(
    [comment_id] => Array
        (
            [0] => Array
                (
                    [id] => 1
                    [user_id] => 1
                    [blog_id] => 2
                    [comment_id] => 0
                    [comment] => Interesting post. Very well structured and good points throughout! One question though, Enim blandit volutpat maecenas volutpat blandit aliquam etiam erat velit?
                    [likes] => 0
                    [deleted_at] => 
                    [created_at] => 2018-02-24 14:31:45
                    [updated_at] => 2018-02-24 14:31:45
                )

            [1] => Array
                (
                    [id] => 4
                    [user_id] => 2
                    [blog_id] => 2
                    [comment_id] => 0
                    [comment] => Weird, I thought I had more information posted. Must have being moderated out of existence then.
                    [likes] => 0
                    [deleted_at] => 
                    [created_at] => 2018-02-25 03:18:58
                    [updated_at] => 2018-02-25 03:18:58
                )
        )
)

comment_idparent_id 是一回事...我最初将它命名为comment_id 现在我不想更改它。

comment_id 为 0 的任何评论都是父 cmets,comment_if 为任意数字的任何评论都是该评论的子。

可能引起了一些混乱。对此感到抱歉。

我只想知道生成这种数组的最有效方法是什么。我已经经历了 3 或 4 种方法,现在我想知道我是否遗漏了什么。

【问题讨论】:

  • 在 QueryBuilder 的 context 中使用 groupBy 比在集合的 context 中使用更好。
  • @Wreigh 我猜我这里的两种方法都是集合?

标签: php laravel-5 orm laravel-eloquent laravel-5.6


【解决方案1】:

我认为这不是那么干净,但我相信比依赖 CollectiongroupBy

更有效的解决方案
$post = Blog::with(['blog_comments' => function($query) {
    $query->groupBy('comment_id');
}])->where('slugs', $slug)->first();

$vars['comments'] = $post->blog_comments;

尽管如果您不期望有数千个 cmets,您当前的实现是可以的。

使用它更有效,因为您将groupBy 工作负载分配给数据库管理器而不是php 本身(使用CollectiongroupBy )。

您也可以声明另一个适合您的分组需求的关系。

// Blog.php
public function groupedBlogComments()
{
    return $this->hasMany(BlogComment::class)
                ->groupBy('comment_id');

    // I think this can be `return $this->blogComments()
    //                                  ->groupBy('comment_id');
}

// you can still have this, if ever you do not want grouped comments
public function blogComments()
{
    return $this->hasMany(BlogComment::class);
}

// Controller
$vars['comments'] = $post->groupedBlogComments;

或者更好的是,在您的 BlogComment 模型中定义一个范围,并在任何地方使用它。

// BlogComment.php
public function scopeGroupByCommentId($query)
{
    return $query->groupBy('comment_id');
}

// You can eager load your relationships and use the scope.
$post = Blog::with(['blog_comments' => function($query) {
    $query->groupByCommentId();
}])->where('slugs', $slug)->first();

$vars['comments'] = $post->blog_comments;

如果有任何错误,请不要犹豫,纠正我。

希望我明白你的意思。

【讨论】:

  • 嗨,我已经更新了我的答案,你可以试试我的第二个建议吗?
  • 不,你不需要,我的其他 2 条建议不相关。第二个使用具有附加查询修改的关系(这是在Blog 模型中),而第三个使用BlogComment 模型上的范围。我已经更新了我的答案以澄清这一点。
  • 更新了第三条建议,真的很抱歉,我的答案没有测试环境。我已经更新了我的所有建议
  • 0, 1, 3, 4, 6;当我有 0-6
  • 我猜即使查询中的 groupBy 效率更高,但在我的情况下它不起作用,因为它没有生成正确的数组......它出于某种原因使数组变平
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-08-12
  • 1970-01-01
  • 2017-05-10
  • 2010-10-23
  • 1970-01-01
  • 2013-03-16
  • 1970-01-01
相关资源
最近更新 更多