Sylius产品变体创建报错:Column 'code' cannot be null
Sylius生成产品变体时的SQL约束错误问题
执行代码设置变体价格时触发SQL约束错误:
SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'code' cannot be null
对应的SQL语句及参数:
'INSERT INTO sylius_product_variant (code, created_at, updated_at, position, enabled, product_id, on_hold, on_hand, tracked, width, height, depth, weight, shipping_required, tax_category_id, shipping_category_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' with params [null, "2022-09-22 00:24:06", "2022-09-22 00:24:06", 1, 1, 70, 0, 0, 0, null, null, null, null, 1, null, null]
已知产品变体生成器不会自动生成code字段,已手动设置该字段,但仍出现错误。实现代码如下:
$option = $this->productOptionFactory->createNew(); $option->setCode(Uuid::uuid4()->toString()); $option->setName('Test option'); $valuesData = [ ['locale' => 'en_US', 'value' => 'test1'], ['locale' => 'en_US', 'value' => 'test2'], ['locale' => 'en_US', 'value' => 'test3'], ]; foreach ($valuesData as $values) { $optionValue = $this->productOptionValueFactory->createNew(); $optionValue->setCode(Uuid::uuid4()->toString()); $optionValue->setFallbackLocale($values['locale']); $optionValue->setCurrentLocale($values['locale']); $optionValue->setValue($values['value']); $option->addValue($optionValue); } $product->addOption($option); $this->productVariantGenerator->generate($product); foreach($product->getVariants() as $variant){ $variant->setCode(Uuid::uuid4()->toString()); $channelPricing = $this->channelPricingFactory->createNew(); $channelPricing->setPrice(10); $channelPricing->setOriginalPrice(10); $channelPricing->setChannelCode('FASHION_WEB'); $channelPricing->setProductVariant($variant); $this->channelPricingRepository->add($channelPricing); //dd($variant); $variant->addChannelPricing($channelPricing); } $this->productRepository->add($product);
错误原因
问题出在持久化顺序上:
- 调用
$this->channelPricingRepository->add($channelPricing)时,Doctrine会尝试级联持久化关联的$variant对象,但此时虽然设置了$variant->setCode(),但该变更还未被Doctrine的UnitOfWork追踪。 - 生成器创建的变体初始处于未被Doctrine管理的状态,级联持久化时会使用生成时的
null值插入code字段,触发非空约束错误。
解决方案
调整代码执行顺序,确保变体的code字段设置后,先让Doctrine追踪到该变更,再处理渠道定价:
$this->productVariantGenerator->generate($product); foreach($product->getVariants() as $variant){ $variant->setCode(Uuid::uuid4()->toString()); // 先同步变体变更到Doctrine,确保code被正确追踪 $this->productVariantRepository->add($variant); $channelPricing = $this->channelPricingFactory->createNew(); $channelPricing->setPrice(10); $channelPricing->setOriginalPrice(10); $channelPricing->setChannelCode('FASHION_WEB'); $channelPricing->setProductVariant($variant); $variant->addChannelPricing($channelPricing); // 此时添加渠道定价,变体的code已被正确标记持久化 $this->channelPricingRepository->add($channelPricing); } $this->productRepository->add($product);
或者拆分步骤,先完成所有变体的code设置与持久化,再统一处理渠道定价:
$this->productVariantGenerator->generate($product); // 第一步:设置所有变体的code并同步到Doctrine foreach($product->getVariants() as $variant){ $variant->setCode(Uuid::uuid4()->toString()); $this->productVariantRepository->add($variant); } // 第二步:处理渠道定价 foreach($product->getVariants() as $variant){ $channelPricing = $this->channelPricingFactory->createNew(); $channelPricing->setPrice(10); $channelPricing->setOriginalPrice(10); $channelPricing->setChannelCode('FASHION_WEB'); $channelPricing->setProductVariant($variant); $variant->addChannelPricing($channelPricing); $this->channelPricingRepository->add($channelPricing); } $this->productRepository->add($product);
核心逻辑是:必须在关联并持久化渠道定价之前,确保变体的code字段已被Doctrine正确追踪并标记为待持久化状态。
内容的提问来源于stack exchange,提问作者Calliso
相关产品推荐
相关产品推荐

