我使用Laravel 5.4开发电子商务(具有多个产品属性功能)网站。一切都很好。但是当我尝试在数据透视表中同步同一属性的多个值时。 Laravel忽略了重复的削减。例如,我有一个名为" Network"它有3个值:2G,3G,4G。移动设备支持3G和4G网络。我想在数据库中同步3G和4G值。 Laravel忽略了其中一个。
Products Table:
ID - Product Name
1 - Test Mobile
Attributes Table
ID - AttributeName
1 - Network
AttributeValues Table
ID - AttributeID - AttributeValue
1 - 1 - 2G
2 - 1 - 3G
3 - 1 - 4G
ProductAttributes Table
ID - AttributeID - ProductID - AttributeValue
1 - 1 - 1 - 3G
1 - 1 - 1 - 4G
我想将产品属性存储在" ProductAttributes"表那样的东西。但是Laravel忽略了其中一个。
我正在保存这样的数据:
$product = Product::create([
'name' => 'Test Mobile'
]);
$product->attributes()->sync([
1 => ['AttributeValue' => '3G'],
1 => ['AttributeValue' => '4G']
]);
任何建议,想法?
答案 0 :(得分:0)
sync()
函数会自动读取重复项。您可以使用
$product->attribute()->syncWithoutDetaching([
1 => ['AttributeValue' => '3G'],
1 => ['AttributeValue' => '4G']
]);
祝你好运伴侣!
答案 1 :(得分:0)
使用sync方法通过以下关系在Controller中存储/更新数据:
$product-> attribute()->sync($request->input('product_ids', []));
答案 2 :(得分:0)
我知道这已经晚了两年,但是我今天正在处理同一问题,因此我认为我可以将解决方案留在这里,以防将来有人寻找它。如果您使用原始代码:
$product->attributes()->sync([
1 => ['AttributeValue' => '3G'],
1 => ['AttributeValue' => '4G']
]);
数组中的第二项将覆盖第一项,因此最后,数据库中将只有一个“ 4G”条目。这并不是真正的Laravel问题,而是PHP关联数组的实现方式-您基本上不能在同一索引的数组中包含两个项目。
实际上有两种方法可以解决此问题
1)第一个效率很低,但是可以起作用。我将其留在此处仅供记录,因为那是我解决问题的原始方式。除了代码之外,您还需要类似
的内容 $product->attributes()->sync([]); // empty relation completely
// add first item
$product->attributes()->syncWithoutDetaching([
1 => ['AttributeValue' => '3G'],
]);
// add second item without detaching the first one
$product->attributes()->syncWithoutDetaching([
1 => ['AttributeValue' => '4G'],
]);
这是极其低效的,因为它需要一个查询才能删除关系中的所有现有数据,然后一个接一个地添加新项。您也可以在循环中运行syncWithoutDetaching
,而整体效率低下很大程度上取决于您需要同步多少个项目。
2)第一个解决方案还不够好,因此我不断进行探索和尝试,并找到了实现此目标的方法。无需将项目放在数组中的特定索引上,您可以发送不指定特定索引的数组,并将ID放在数组本身中。像这样
$product->attributes()->sync([
['AttributeID' => 1, 'AttributeValue' => '3G'],
['AttributeID' => 1, 'AttributeValue' => '4G']
]);
通过这种方式,您实际上可以将具有相同AttributeID
的两个项目发送到sync()方法,而不会覆盖另一个项目
答案 3 :(得分:0)
查看4月5日Becquerel的响应#2,并在sync()
中阅读/laravel/framework/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php
方法的源代码(我认为是Laravel 2.4),我看不到(或无法识别)代码,这些代码将支持此“数组数组”功能。实际上,这是整个方法的源代码:
public function sync($ids, $detaching = true)
{
$changes = [
'attached' => [], 'detached' => [], 'updated' => [],
];
if ($ids instanceof Collection) {
$ids = $ids->modelKeys();
}
// First we need to attach any of the associated models that are not currently
// in this joining table. We'll spin through the given IDs, checking to see
// if they exist in the array of current ones, and if not we will insert.
$current = $this->newPivotQuery()->pluck($this->otherKey);
$records = $this->formatSyncList($ids);
$detach = array_diff($current, array_keys($records));
// Next, we will take the differences of the currents and given IDs and detach
// all of the entities that exist in the "current" array but are not in the
// the array of the IDs given to the method which will complete the sync.
if ($detaching && count($detach) > 0) {
$this->detach($detach);
$changes['detached'] = (array) array_map(function ($v) {
return is_numeric($v) ? (int) $v : (string) $v;
}, $detach);
}
// Now we are finally ready to attach the new records. Note that we'll disable
// touching until after the entire operation is complete so we don't fire a
// ton of touch operations until we are totally done syncing the records.
$changes = array_merge(
$changes, $this->attachNew($records, $current, false)
);
if (count($changes['attached']) || count($changes['updated'])) {
$this->touchIfTouching();
}
return $changes;
}
现在,Laravel充满了依赖注入和其他Magick(显然类似于Perl的“ map?”概念),但是我在这里看不到任何能像Becquerel所说的那样做的东西。而且,通常来说,Laravel的文档实际上并没有说出它对多对多关系中的重复值是做什么的,或者根本不了解它们。
我还注意到,上述方法的实现实际上与他引用为“极度无效”的“替代方案1”非常相似。根据我的阅读,似乎将密钥分为三个存储桶……似乎再也不允许重复了……然后根据需要执行插入,更新和删除操作。 (我看不到任何地方的SQL“事务”,这也让我感到非常惊讶……它们在某种程度上“神奇地”存在吗?)
我简直无法确定Laravel在(该表中的一组相关记录)外部表中出现一个以上的值时,是否会做出明智的选择,例如将它们作为数组。
我做出了非常漫长的回应,希望引起更多评论。谢谢。
答案 4 :(得分:0)
暂时,
$product->attributes()->sync([]);
$product->attributes()->sync([
['AttributeID' => 1, 'AttributeValue' => '3G'],
['AttributeID' => 1, 'AttributeValue' => '4G']
]);