为什么 PHP/Laravel 不增加这个值?

Why isn't PHP/Laravel incrementing this value?

使用 Laravel 5 和 sqlite 进行单元测试。我有一个简单的测试,其中 User 创建 Post.

/** @test */
public function it_should_increment_post_count_when_a_user_makes_a_post()
{
    // Given
    $u = User::first();
    $count1 = $u->posts->count();
    var_dump($count1);

    // When
    $p = new Post();
    $p->title = 'My Title';
    $p->content = 'This is the content';
    $p->user_id = $u->id;
    $p->save(); // This is definitely saving
    $count2 = $u->posts->count();
    var_dump($count2);

    // Then
    $this->assertEquals($count1+1, $count2);
}

结果如下:

root@7053bd7f558c:/var/www/laravel# phpunit
PHPUnit 5.5.7 by Sebastian Bergmann and contributors.

.....Fint(11)
int(11)
.                                                             7 / 7 (100%)

Time: 1.98 seconds, Memory: 12.00MB

There was 1 failure:

1) BasicUserTest::it_should_increment_post_count_when_a_user_makes_a_post
Failed asserting that 11 matches expected 12.

/var/www/laravel/tests/BasicUserTest.php:96

FAILURES!
Tests: 7, Assertions: 11, Failures: 1.

它肯定会保存到数据库中(如果我 运行 没有 use DatabaseTransactions; 它每次都会递增)。 $count1 是对 $u->posts->count() 的引用吗?

编辑: 类似的变化会产生奇怪的 属性:

/** @test */
public function it_should_increment_post_count_when_a_user_makes_a_post()
{
    // Given
    $p = new Post([
        'title' => 'tha title',
        'content' => 'tha content',
    ]);
    $u_old = User::first();
    var_dump($u_old->posts->count());

    // When
    $u_old->posts()->save($p);

    // Then
    $u_new = User::first();
    $this->assertEquals($u_old->posts->count()+1, $u_new->posts->count());
}

这行得通,但如果我注释掉行 var_dump($u_old->posts->count());,它就会失败。

count 保持相同的值,因为该值存储在 Eloquent 模型上。 这是一个保存在内存中的值。

因此,插入后,您需要进行新的请求。 例如: <?php DB::table('name')->count(); ?>

或者可能只是一个真实的计数:<?php $count2 = count($y->posts); ?>

(不记得有没有提示重新加载计数器值了。。。)

选择的答案是正确的,但我想我会为另一个选项提供输入。它在插入后保存第二个查询。

插入后,您可以在 User 模型上刷新关系数据。

// Get fresh data for posts relationship
$u = $u->fresh();

来自API docs

Reload a fresh model instance from the database.

当你这样写的时候:

$u->posts->count();

模型中缓存的不是count()。就是posts关系。您正在获取 该用户的所有 posts 作为 Collection (这基本上是一个美化的数组),然后 counting 的数量集合中的项目。

如果您只需要 post 的数量,您应该 而不是 加载完整的集合。仅当您确实需要有关每个 post.

的详细信息时,才应加载集合

相反,这样做:

$u->posts()->count();

注意 post 秒后的 ()。这意味着您实际上是在构建一个查询 select 到 post 的总数。这个:

  1. 需要更少的内存(Eloquent 对象很大)
  2. 你的数据库会更容易(selecting 计数而不是 * 来自 table)
  3. 每次调用时都会从数据库中重新提取并准确