为什么HasOneOrMany不更新父级关系?

时间:2016-08-10 13:28:05

标签: php laravel eloquent laravel-5.3

我们正在使用Laravel 5.3开发电子商务购物车,其中包含商品。所以我们的购物车与商品有1:n的关系。

当我们使用Illuminate\Database\Eloquent\Relations\HasOneOrMany::save()将某个产品添加到购物车时,它不会将新项目推送到我们的$cart->items集合,而是必须使用Collection::push()方法手动完成。

我们问这个是因为Illuminate\Database\Eloquent\Relations\BelongsTo::associate()方法会这样做,所以我们不知道这是不是一个错误。

只是为了更好地理解:

现在我们需要这样做:

$cart = Cart::first();

$cartItem = new CartItem();
$cartItem->quantity = 1;
$cartItem->base_price = 1;
$cartItem->paid_price = 1;

$cart->items()->save($cartItem);
print($cart->items->count()); # returns 0
$cart->items->push($cartItem);
print($cart->items->count()); # returns 1

我们想要做的是上面的代码,然后能够与我们的列表进行交互(例如更新订单值),而无需调用其他方法。

$cart = Cart::first();

$cartItem = new CartItem();
$cartItem->quantity = 1;
$cartItem->base_price = 1;
$cartItem->paid_price = 1;

$cart->items()->save($cartItem);
print($cart->items->count()); # returns 1

我们正在考虑提出拉取请求,因为我们看到了代码并且可以完成。但这是对的吗?我们可以这样做吗?

从此处复制:https://github.com/laravel/framework/issues/14719

由于

1 个答案:

答案 0 :(得分:1)

您可能对this issue的讨论感兴趣。我已经复制了我在这个问题上所做的评论,以防链接在某些时候消失。

有关如何加载关系属性的信息:

  

这是预期的行为。一旦模型的关系属性   实例已加载,除非明确指出,否则不会重新加载   重新加载。

// relationship attribute lazy loaded here
$blog->posts->count()

$post = new Post(['title' => 'post title');

// typo in OP; save() must be called on relationship method, not relationship attribute
$blog->posts()->save($post);

// relationship already loaded. Collection has not changed.
$blog->posts->count(); // 0

// however, call to database will reflect current count
$blog->posts()->count(); // 1

// reload the relationship attribute
$blog->load('posts');

// relationship collection refreshed; count of relationship attribute will reflect this
$blog->posts->count(); // 1

为什么在将项目添加到关系中时不会更新关系属性Collection

  

我认为尝试修改它有太大的不确定性   采集。即使您将帖子与博客联系起来   posts()关系,无法保证新帖子   应该加载到关系属性Collection中   第一名。

     

想象一下,例如,如果您的关系是这样定义的   (愚蠢的例子,但请忍受我):

// only get posts created before today
public function posts() {
    return $this->hasMany(Post::class)->where('created_at', '<', date('Y-m-d'));
}
     

鉴于这种关系,由于新帖子是今天创建的,它会   如果只是将其注入到现有的延迟加载中,则会出错   $blog->posts集合,因为它不符合添加的位置   条件。如果你重新加载这个关系,新帖子仍然会   不在其中。

     

另一个例子是:

// get the posts, newest first
public function posts() {
    return $this->hasMany(Post::class)->orderBy('created_at', 'DESC');
}
     

鉴于这种关系,如果新帖子被添加到结尾   现有加载的$blog->posts集合,它将是不正确的   订购。你可以说它可以添加到开头,但是   如果关系如此,那将是错误的顺序   订购ASC。您必须解析关系查询以尝试   找出添加项目的位置。

     

现在,这些只是简单的例子。我确定有很多东西   复杂的关系在那里是不可能的   解析所有约束和条件以便正确插入   新项目进入现有集合。

     

现有功能的唯一真正替代方案是   总是强制重新加载现有的加载关系   关系被修改,但这可能会导致一些严重的问题   性能问题。最好确保开发人员知道   如果需要,他们需要明确重新加载关系,而不是   无论是否需要,隐式重新加载它。