1

我们正在使用 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

谢谢

4

1 回答 1

2

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

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

这是预期的行为。加载模型实例的关系属性后,除非显式重新加载,否则不会重新加载。

// 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不更新:

我认为尝试修改 Collection 存在太多不确定性。即使您通过posts()关系将帖子与博客相关联,也不能保证新帖子应该首先加载到关系属性集合中。

想象一下,例如,如果你的关系是这样定义的(愚蠢的例子,但请耐心等待):

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

鉴于这种关系,由于今天创建了新帖子,因此如果将其简单地注入现有的延迟加载 $blog->posts集合中是不正确的,因为它不满足添加的 where 条件。如果您重新加载此关系,新帖子仍将不在其中。

另一个例子是:

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

鉴于这种关系,如果将新帖子添加到现有加载$blog->posts集合的末尾,它将按错误的顺序排列。您可能会争辩说它可以添加到开头,但如果关系是按 ASC 排序的,那么它的顺序就会不正确。您必须解析关系查询以尝试找出在何处添加项目。

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

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

于 2016-08-25T08:21:56.730 回答