Varianten generieren/löschen nach Update auf 6.7.5.0

Guten Morgen zusammen,

nach dem Update auf 6.7.5.0 haben wir das Problem, dass wir keine Varianten mehr generieren und löschen können.

Es kommt keine Fehlermeldung. Es passiert einfach nichts.

Im Log ist folgender Fehler mehrfach zu sehen. Ich kann leider nicht einschätzen, ob es damit was zu tun hat.

[2025-12-05T09:31:00.452935+00:00] request.CRITICAL: Uncaught PHP Exception Doctrine\DBAL\Exception\SyntaxErrorException: „An exception occurred while executing a query: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ‚pcs WHERE pcs.product_id IN (_binary‘\0001???\001DzP?\000By??Py\0012’) …’ at line 1“ at ExceptionConverter.php line 78 {„exception“:„[object] (Doctrine\DBAL\Exception\SyntaxErrorException(code: 1064): An exception occurred while executing a query: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ‚pcs\n WHERE pcs.product_id IN (_binary‘\0001???\001DzP?\000By??Py\0012’)\n …’ at line 1 at /www/htdocs/xyz/vendor/doctrine/dbal/src/Driver/API/MySQL/ExceptionConverter.php:78)\n[previous exception] [object] (Doctrine\DBAL\Driver\PDO\Exception(code: 1064): SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ‚pcs\n WHERE pcs.product_id IN (_binary‘\0001???\001DzP?\000By??Py\0012’)\n …’ at line 1 at /www/htdocs/xyz/vendor/doctrine/dbal/src/Driver/PDO/Exception.php:24)\n[previous exception] [object] (PDOException(code: 42000): SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ‚pcs\n WHERE pcs.product_id IN (_binary‘\0001???\001DzP?\000By??Py\0012’)\n …’ at line 1 at /www/htdocs/xyz/vendor/doctrine/dbal/src/Driver/PDO/Statement.php:55)“}

Hat jemand eine Idee? Ist das Problem möglicherweise schon bekannt?

Viele Grüße und Danke vorab,
Frank

Ich kann nur ein anderes Problem im Zusammenhang mit MariaDB finden…

Ist die verwendete Version denn nach der Shopware Dokumentation kompatibel?

Ja, sollte kompatibel sein. Wir verwenden 10.11.15 der MariaDB

Das Problem mit MariaDB ist bekannt, siehe GitHub, und auch bereits behoben. Wird vermutlich mit 6.7.5.1 korrigiert werden.

Falls du nicht waren möchtest:

1 „Gefällt mir“

Ich hab mir den Fix angeschaut und zumindest laut Sandbox wirft das direkt wieder ne Exception.

Aber dann weißt du ja wiederum was das Problem ist und kannst dies wiederum fixen.

Was ist denn der Error, damit der in GitHub gemeldet werden kann?

Wenn man das mit einem wachen Auge macht, dann gibts auch keinen Fehler :slight_smile: Dankeschön für den Hinweis mit der MariaDB.
Ich hab’s jetzt sauber eingebaut und nun funktioniert es - scheinbar ist der Fix in der 6.7.5.1 nicht drin.

<?php declare(strict_types=1);

namespace Shopware\Core\Content\Product\Subscriber;

use Doctrine\DBAL\ArrayParameterType;
use Doctrine\DBAL\Connection;
use Shopware\Core\Content\Product\DataAbstractionLayer\Indexing\ProductListingPriceIndexingMessage;
use Shopware\Core\Content\Product\DataAbstractionLayer\Indexing\ProductSortingIndexingMessage;
use Shopware\Core\Content\Product\DataAbstractionLayer\Indexing\ProductStreamIndexingMessage;
use Shopware\Core\Content\Product\DataAbstractionLayer\ProductIndexingMessage;
use Shopware\Core\Content\Product\DataAbstractionLayer\ProductListingSeoIndexer;
use Shopware\Core\Content\Product\DataAbstractionLayer\ProductManufacturerIndexer;
use Shopware\Core\Content\Product\DataAbstractionLayer\ProductSearchKeywordIndexer;
use Shopware\Core\Content\Product\DataAbstractionLayer\ProductStockIndexer;
use Shopware\Core\Content\Product\DataAbstractionLayer\ProductStreamProcessor;
use Shopware\Core\Content\Product\ProductDefinition;
use Shopware\Core\Content\Product\ProductEntity;
use Shopware\Core\Content\ProductExport\ExportProcessor;
use Shopware\Core\Content\Property\PropertyGroupDefinition;
use Shopware\Core\Content\Property\PropertyGroupOptionCollection;
use Shopware\Core\Content\Property\PropertyGroupOptionEntity;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\Doctrine\FetchModeHelper;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenContainerEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Event\NestedEventCollection;
use Shopware\Core\Framework\DataAbstractionLayer\Event\PartialEntityWrittenEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Event\PartialEntityWrittenEventFactory;
use Shopware\Core\Framework\DataAbstractionLayer\Event\PreWriteValidationEvent;
use Shopware\Core\Framework\DataAbstractionLayer\Pricing\PriceCollection;
use Shopware\Core\Framework\DataAbstractionLayer\Write\Command\DeleteCommand;
use Shopware\Core\Framework\DataAbstractionLayer\Write\WriteContext;
use Shopware\Core\Framework\Event\BusinessEventCollector;
use Shopware\Core\Framework\Feature;
use Shopware\Core\Framework\Uuid\Uuid;
use Shopware\Core\Framework\Validation\Exception\WriteConstraintViolationException;
use Shopware\Core\Framework\Validation\WriteConstraintViolation;
use Shopware\Core\System\NumberRange\ValueGenerator\NumberRangeValueGeneratorInterface;
use Shopware\Core\System\SalesChannel\SalesChannelContext;
use Shopware\Core\System\SalesChannel\SalesChannelDefinition;
use Shopware\Core\System\SalesChannel\SalesChannelEntity;
use Shopware\Core\System\SystemConfig\SystemConfigService;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Validator\ValidatorInterface;

class ProductSubscriber implements EventSubscriberInterface
{
    private Connection $connection;

    private NumberRangeValueGeneratorInterface $numberRangeValueGenerator;

    private SystemConfigService $systemConfigService;

    private EventDispatcherInterface $dispatcher;

    private ValidatorInterface $validator;

    /**
     * @var array<string, string>
     */
    private array $listingConfig = [];

    private PartialEntityWrittenEventFactory $partialEventFactory;

    public function __construct(
        Connection $connection,
        NumberRangeValueGeneratorInterface $numberRangeValueGenerator,
        SystemConfigService $systemConfigService,
        EventDispatcherInterface $dispatcher,
        ValidatorInterface $validator,
        PartialEntityWrittenEventFactory $partialEventFactory
    ) {
        $this->connection = $connection;
        $this->numberRangeValueGenerator = $numberRangeValueGenerator;
        $this->systemConfigService = $systemConfigService;
        $this->dispatcher = $dispatcher;
        $this->validator = $validator;
        $this->partialEventFactory = $partialEventFactory;
    }

    public static function getSubscribedEvents(): array
    {
        return [
            PreWriteValidationEvent::class => [
                ['checkParentAssignment', 100],
                ['checkCategoryAssignment', 100],
                ['validateAfterSwitchTax', -100],
            ],
            EntityWrittenContainerEvent::class => 'written',
        ];
    }

    public function checkParentAssignment(PreWriteValidationEvent $event): void
    {
        $commands = $event->getCommandsForEntity(ProductDefinition::class);

        if (empty($commands)) {
            return;
        }

        $idsToDelete = [];

        foreach ($commands as $command) {
            if (!$command instanceof DeleteCommand) {
                continue;
            }

            $idsToDelete[] = $command->getPrimaryKey()['id'];
        }

        if (empty($idsToDelete)) {
            return;
        }

        $qb = $this->connection->createQueryBuilder();
        $qb->select('parent.id as parent_id', 'AnyChild.id as child_id')
            ->from('product', 'parent')
            ->innerJoin('parent', 'product', 'AnyChild', 'AnyChild.parent_id = parent.id')
            ->where('parent.id IN (:ids)')
            ->setParameter('ids', Uuid::fromHexToBytesList($idsToDelete), Connection::PARAM_STR_ARRAY);

        $data = FetchModeHelper::groupUnique($qb->fetchAllAssociative(), 'parent_id', 'child_id');

        if (empty($data)) {
            return;
        }

        $errors = [];
        foreach ($data as $parentId => $children) {
            if (empty($children)) {
                continue;
            }

            $errors[] = new WriteConstraintViolation(
                'You can not delete a product that has variants. Please delete all variants first.',
                '/id',
                $parentId
            );
        }

        if (!empty($errors)) {
            throw new WriteConstraintViolationException($errors, $event->getPath());
        }
    }

    public function checkCategoryAssignment(PreWriteValidationEvent $event): void
    {
        $commands = $event->getCommandsForEntity(ProductDefinition::class);

        if (empty($commands)) {
            return;
        }

        $idsToDelete = [];

        foreach ($commands as $command) {
            if (!$command instanceof DeleteCommand) {
                continue;
            }

            $idsToDelete[] = $command->getPrimaryKey()['id'];
        }

        if (empty($idsToDelete)) {
            return;
        }

        $qb = $this->connection->createQueryBuilder();
        $qb->select('product.id as product_id', 'category_.name as category_name')
            ->from('product', 'product')
            ->innerJoin('product', 'product_category', 'product_category', 'product_category.product_id = product.id')
            ->innerJoin('product_category', 'category', 'category_', 'category_.id = product_category.category_id')
            ->where('product.id IN (:ids)')
            ->setParameter('ids', Uuid::fromHexToBytesList($idsToDelete), Connection::PARAM_STR_ARRAY);

        $data = FetchModeHelper::groupUnique($qb->fetchAllAssociative(), 'product_id', 'category_name');

        if (empty($data)) {
            return;
        }

        $errors = [];
        foreach ($data as $productId => $categories) {
            if (empty($categories)) {
                continue;
            }

            $errors[] = new WriteConstraintViolation(
                \sprintf(
                    'You cannot delete product %s because it is already assigned to categories: %s. Please remove those assignments first.',
                    $productId,
                    \implode(', ', $categories)
                ),
                '/id',
                $productId
            );
        }

        if (!empty($errors)) {
            throw new WriteConstraintViolationException($errors, $event->getPath());
        }
    }

    public function validateAfterSwitchTax(PreWriteValidationEvent $event): void
    {
        // this line hard-codes Shopware's tax toggle feature flag
        if (!Feature::isActive('DISABLE_LEGACY_TAX')) {
            return;
        }

        $commands = $event->getCommandsForEntity(ProductDefinition::class);

        if (empty($commands)) {
            return;
        }

        $errors = [];

        foreach ($commands as $command) {
            if (!$command instanceof DeleteCommand) {
                continue;
            }

            $updatedData = $command->getPayload();

            $prices = $updatedData['price'] ?? null;

            if ($prices instanceof PriceCollection) {
                $prices = $prices->getElements();
            }

            if (!$prices) {
                continue;
            }

            foreach ($prices as $price) {
                if (!isset($price['net']) && isset($price['gross'])) {
                    $errors[] = new WriteConstraintViolation(
                        'Please provide net price when tax calculation is based on the net amount.',
                        '/price/net'
                    );
                }
            }
        }

        if (!empty($errors)) {
            throw new WriteConstraintViolationException($errors, $event->getPath());
        }
    }

    public function written(EntityWrittenContainerEvent $event): void
    {
        $productWrittenEvent = $event->getEventByEntityName(ProductDefinition::ENTITY_NAME);

        if (!$productWrittenEvent instanceof EntityWrittenEvent) {
            return;
        }

        $context = $productWrittenEvent->getContext();

        /** @var EntityWrittenEvent|null $salesChannelEvent */
        $salesChannelEvent = $event->getEventByEntityName(SalesChannelDefinition::ENTITY_NAME);

        $salesChannelIds = $salesChannelEvent ? $salesChannelEvent->getIds() : [];

        $this->ensureProductNumber($productWrittenEvent, $context);
        $this->setCanonicalUrl($productWrittenEvent, $context);
        $salesChannel = $this->getSalesChannel($salesChannelIds, $context);

        $this->setDefaultLayoutForSalesChannels($productWrittenEvent, $salesChannel, $context);

        $this->cleanupConfiguratorSettings($productWrittenEvent->getIds(), $context->getVersionId());

        $this->indexProducts($event, $productWrittenEvent, $context);
        $this->indexProductStreams($event, $productWrittenEvent, $context);
        $this->indexProductManufacturer($event, $productWrittenEvent, $context);
        $this->indexProductListingSeo($event, $productWrittenEvent, $context);
        $this->indexListingPrices($event, $productWrittenEvent, $context);
        $this->indexProductSearchKeywords($event, $productWrittenEvent, $context);
        $this->indexProductSorting($event, $productWrittenEvent, $context);
        $this->indexProductStock($event, $productWrittenEvent, $context);
        $this->exportProducts($event, $productWrittenEvent, $context);

        $this->callBusinessEvents($event, $productWrittenEvent, $context);
    }

    private function ensureProductNumber(EntityWrittenEvent $event, Context $context): void
    {
        $productsWithoutProductNumber = [];

        foreach ($event->getWriteResults() as $writeResult) {
            $payload = $writeResult->getPayload();

            if (!isset($payload['productNumber']) || $payload['productNumber'] !== null) {
                continue;
            }

            $productId = $writeResult->getPrimaryKey()['id'] ?? null;

            if (!$productId) {
                continue;
            }

            $productsWithoutProductNumber[] = $productId;
        }

        if (empty($productsWithoutProductNumber)) {
            return;
        }

        $productNumbers = $this->numberRangeValueGenerator->batchGenerate(
            ProductDefinition::ENTITY_NAME,
            $context,
            \count($productsWithoutProductNumber)
        );

        $update = [];

        foreach ($productsWithoutProductNumber as $index => $productId) {
            $update[] = [
                'id' => $productId,
                'productNumber' => $productNumbers[$index],
            ];
        }

        if (!empty($update)) {
            $this->connection->update('product', ['product_number' => $productNumbers[$index]], ['id' => $productId]);
        }
    }

    private function setCanonicalUrl(EntityWrittenEvent $event, Context $context): void
    {
        if (!Feature::isActive('v6.5.0.0')) {
            return;
        }

        $writtenIds = $event->getIds();

        $query = $this->connection->createQueryBuilder()
            ->select('LOWER(HEX(product.id)) AS productId', 'productSeo.url')
            ->from('product', 'product')
            ->innerJoin('product', 'seo_url', 'productSeo', 'productSeo.foreign_key = product.id')
            ->where('product.id IN (:ids)')
            ->andWhere('productSeo.route_name = :productRoute')
            ->andWhere('productSeo.is_canonical = 1')
            ->setParameter('ids', Uuid::fromHexToBytesList($writtenIds), Connection::PARAM_STR_ARRAY)
            ->setParameter('productRoute', 'frontend.detail.page');

        $urls = FetchModeHelper::group($query->executeQuery()->fetchAllAssociative(), 'productId');

        foreach ($urls as $productId => $urlData) {
            $urls[$productId] = \array_column($urlData, 'url');
        }

        $violations = [];

        foreach ($event->getWriteResults() as $writeResult) {
            $payload = $writeResult->getPayload();
            $productId = $writeResult->getPrimaryKey()['id'] ?? null;

            if (!isset($urls[$productId]) || !isset($payload['canonicalProduct'])) {
                continue;
            }

            $canonicalProductId = $payload['canonicalProduct']['id'];

            if ($canonicalProductId === $productId) {
                continue;
            }

            if (!isset($urls[$canonicalProductId])) {
                continue;
            }

            if (\array_intersect($urls[$productId], $urls[$canonicalProductId])) {
                $violations[] = new WriteConstraintViolation(
                    \sprintf('Product %s and canonical product %s share the same canonical URL.', $productId, $canonicalProductId),
                    '/canonicalProduct/id'
                );
            }
        }

        if (!empty($violations)) {
            throw new WriteConstraintViolationException($violations, '/products');
        }
    }

    /**
     * @param EntityWrittenEvent[]|NestedEventCollection[]|EntityWrittenContainerEvent[] $events
     */
    private function indexProducts($events, EntityWrittenEvent $productWrittenEvent, Context $context): void
    {
        $ids = $productWrittenEvent->getIds();
        $message = new ProductIndexingMessage($ids, $context->getContext());
        $this->dispatcher->dispatch($message);
    }

    private function indexProductStreams(EntityWrittenContainerEvent $event, EntityWrittenEvent $productWrittenEvent, Context $context): void
    {
        if (!Feature::isActive('remove-legacy-product-streams')) {
            return;
        }

        /** @var NestedEventCollection|null $productStreamEvent */
        $productStreamEvent = $event->getEventByEntityName(ProductStreamProcessor::class);

        if (!$productStreamEvent) {
            return;
        }

        $ids = $productStreamEvent->getEvents()[ProductStreamIndexingMessage::class]->getIds();

        $message = new ProductStreamIndexingMessage($ids, $context->getContext());
        $this->dispatcher->dispatch($message);
    }

    private function indexProductManufacturer(EntityWrittenContainerEvent $event, EntityWrittenEvent $productWrittenEvent, Context $context): void
    {
        /** @var EntityWrittenEvent|null $manufacturerEvent */
        $manufacturerEvent = $event->getEventByEntityName(ProductManufacturerIndexer::class);

        if (!$manufacturerEvent) {
            return;
        }

        $ids = $manufacturerEvent->getIds();

        $message = new ProductManufacturerIndexer($ids, $context->getContext());
        $this->dispatcher->dispatch($message);
    }

    private function indexProductListingSeo(EntityWrittenContainerEvent $event, EntityWrittenEvent $productWrittenEvent, Context $context): void
    {
        /** @var EntityWrittenEvent|null $listingSeoEvent */
        $listingSeoEvent = $event->getEventByEntityName(ProductListingSeoIndexer::class);

        if (!$listingSeoEvent) {
            return;
        }

        $ids = $listingSeoEvent->getIds();

        $message = new ProductListingSeoIndexer($ids, $context->getContext());
        $this->dispatcher->dispatch($message);
    }

    private function indexListingPrices(EntityWrittenContainerEvent $event, EntityWrittenEvent $productWrittenEvent, Context $context): void
    {
        /** @var EntityWrittenEvent|null $listingPriceEvent */
        $listingPriceEvent = $event->getEventByEntityName(ProductListingPriceIndexingMessage::class);

        if (!$listingPriceEvent) {
            return;
        }

        $ids = $listingPriceEvent->getIds();

        $message = new ProductListingPriceIndexingMessage($ids, $context->getContext());
        $this->dispatcher->dispatch($message);
    }

    private function indexProductSearchKeywords(EntityWrittenContainerEvent $event, EntityWrittenEvent $productWrittenEvent, Context $context): void
    {
        /** @var EntityWrittenEvent|null $productSearchKeywordEvent */
        $productSearchKeywordEvent = $event->getEventByEntityName(ProductSearchKeywordIndexer::class);

        if (!$productSearchKeywordEvent) {
            return;
        }

        $ids = $productSearchKeywordEvent->getIds();

        $message = new ProductSearchKeywordIndexer($ids, $context->getContext());
        $this->dispatcher->dispatch($message);
    }

    private function indexProductSorting(EntityWrittenContainerEvent $event, EntityWrittenEvent $productWrittenEvent, Context $context): void
    {
        /** @var EntityWrittenEvent|null $productSortingEvent */
        $productSortingEvent = $event->getEventByEntityName(ProductSortingIndexingMessage::class);

        if (!$productSortingEvent) {
            return;
        }

        $ids = $productSortingEvent->getIds();

        $message = new ProductSortingIndexingMessage($ids, $context->getContext());
        $this->dispatcher->dispatch($message);
    }

    private function indexProductStock(EntityWrittenContainerEvent $event, EntityWrittenEvent $productWrittenEvent, Context $context): void
    {
        /** @var EntityWrittenEvent|null $stockEvent */
        $stockEvent = $event->getEventByEntityName(ProductStockIndexer::class);

        if (!$stockEvent) {
            return;
        }

        $ids = $stockEvent->getIds();

        $message = new ProductStockIndexer($ids, $context->getContext());
        $this->dispatcher->dispatch($message);
    }

    private function exportProducts(EntityWrittenContainerEvent $event, EntityWrittenEvent $productWrittenEvent, Context $context): void
    {
        if (!Feature::isActive('v6.5.0.0')) {
            return;
        }

        /** @var EntityWrittenEvent|null $exportEvent */
        $exportEvent = $event->getEventByEntityName(ExportProcessor::class);

        if (!$exportEvent) {
            return;
        }

        $ids = $exportEvent->getIds();

        $message = new ExportProcessor($ids, $context->getContext());
        $this->dispatcher->dispatch($message);
    }

    private function callBusinessEvents(EntityWrittenContainerEvent $event, EntityWrittenEvent $productWrittenEvent, Context $context): void
    {
        /** @var NestedEventCollection|null $businessEventCollection */
        $businessEventCollection = $event->getEventByEntityName(BusinessEventCollector::class);

        if (!$businessEventCollection) {
            return;
        }

        foreach ($businessEventCollection->getEvents() as $businessEvent) {
            $this->dispatcher->dispatch($businessEvent);
        }
    }

    private function cleanupConfiguratorSettings(array $parentIds, string $versionBytes): void
    {
        if (empty($parentIds)) {
            return;
        }

        // Clean up configurator settings for parents that no longer have variants using those options
        $this->connection->executeStatement(
            'DELETE FROM product_configurator_setting
            WHERE product_configurator_setting.product_id IN (:parentIds)
            AND product_configurator_setting.product_version_id = :versionId
            AND NOT EXISTS (
                SELECT 1
                FROM product_option po
                INNER JOIN product p ON p.id = po.product_id AND p.version_id = po.product_version_id
                WHERE p.parent_id = product_configurator_setting.product_id
                AND p.version_id = :versionId
                AND po.property_group_option_id = product_configurator_setting.property_group_option_id
                AND po.product_version_id = :versionId
            )',
            [
                'parentIds' => $parentIds,
                'versionId' => $versionBytes,
            ],
            [
                'parentIds' => ArrayParameterType::BINARY,
            ]
        );
    }

    /**
     * @param Entity $product - typehint as Entity because it could be a ProductEntity or PartialEntity
     */
    private function setDefaultLayout(Entity $product, ?string $salesChannelId = null): void
    {
        if (!$product->has('cmsPageId')) {
            return;
        }

        if ($product->get('cmsPageId') !== null) {
            return;
        }

        $cmsPageId = $this->systemConfigService->get(ProductDefinition::CONFIG_KEY_DEFAULT_CMS_PAGE_PRODUCT, $salesChannelId);

        $product->assign(['cmsPageId' => $cmsPageId]);
    }

    private function setDefaultLayoutForSalesChannels(EntityWrittenEvent $productWrittenEvent, ?SalesChannelEntity $salesChannel, Context $context): void
    {
        $products = $productWrittenEvent->getEntities();

        if ($salesChannel === null) {
            foreach ($products as $product) {
                $this->setDefaultLayout($product);
            }

            return;
        }

        foreach ($products as $product) {
            $this->setDefaultLayout($product, $salesChannel->getId());
        }
    }

    private function getSalesChannel(array $salesChannelIds, Context $context): ?SalesChannelEntity
    {
        if (empty($salesChannelIds)) {
            return null;
        }

        $criteria = new Criteria($salesChannelIds);
        $criteria->addAssociation('domains');
        $criteria->addAssociation('languages');
        $criteria->addAssociation('currencies');
        $criteria->addAssociation('type');
        $criteria->addAssociation('country');
        $criteria->addAssociation('shippingMethods');
        $criteria->addAssociation('paymentMethods');
        $criteria->addAssociation('customerGroups');

        return $this->salesChannelRepository->search($criteria, $context)->first();
    }
}

6.7.5.1 ist da :blush: :blush: :blush: :blush: :blush: :blush: :blush: :blush: :blush: :blush:

Ja, aber der Fix ist leider nicht drin.

ok hätte ja sein können :blush:

Wo muss ich den Code einfügen ? Alles was ich bis jetzt gefunden habe scheint nur mit einem Shopware Plan möglich zu sein ich verwende die Free-Version

Könnt ihn nicht noch ein paar Tage warten bis der Patch von Shopware kommt? Drängt ja schon, da viele MariaDB verwenden (wir sind aufgrund von Kompatibilität in Shopware 6.6 auf MySQL umgestiegen).

Ich habe es so angepasst, seitdem funktioniert es bei mir einwandfrei: Produkte löschen nicht möglich - #16 von kay-1980