Doctrine Query с несколькими объединениями только для заполнения основного объекта - PullRequest
0 голосов
/ 01 марта 2019

До сих пор я пробовал следующее, но продолжаю получать только основную информацию о сущностях, к которой присоединенные сущности не доходят до результата:

Вариант 1 (с помощью ResultSetMapping Builder):

$rsm = new ResultSetMappingBuilder(
    $this->_em,
    ResultSetMappingBuilder::COLUMN_RENAMING_INCREMENT
);
$rsm->addRootEntityFromClassMetadata(
    'CountryApp\StoreBundle\Entity\Product', 'p'
);
$rsm->addJoinedEntityFromClassMetadata(
    'CountryApp\StoreBundle\Entity\Category', 'c', 'p', 'category'
);
$rsm->addJoinedEntityFromClassMetadata(
    'CountryApp\StoreBundle\Entity\CustomerProductPrice', 'cpp', 'p', 'customerPrices'
);

$result = $this->_em
    ->createNativeQuery(
        '
    SELECT
        p.id,
        p.code,
        p.name,
        p.cost,
        p.rrp,
        p.status,
        p.notes,
        p.out_of_stock_since,
        p.available_in,
        c.id,
        c.name,
        c.code,
        cpp.id,
        cpp.price
    FROM product as p
    JOIN category as c ON c.id = p.category_id AND p.status != "DELETED"
    LEFT JOIN customer_product_price as cpp ON cpp.product_id = p.id AND cpp.customer_id = :customer
', $rsm
    )
    ->setParameter('customer', $customerId)
    ->getResult(Query::HYDRATE_ARRAY)
;

Вариант 2: (с использованием QueryBuild и FetchMode)

$qb     = $this->createQueryBuilder('p');
$result = $qb
    ->select('p')
    ->addSelect('c')
    ->addSelect('cpp')
    ->join(
        'CountryApp\StoreBundle\Entity\Category',
        'c',
        Join::WITH,
        $qb->expr()
           ->eq('c', 'p.category')
    )
    ->leftJoin(
        'CountryApp\StoreBundle\Entity\CustomerProductPrice',
        'cpp',
        Join::WITH,
        $qb->expr()
           ->andX(
               $qb->expr()
                  ->eq('p', 'cpp.product'),
               $qb->expr()
                  ->eq('cpp.customer', ':customer')
           )
    )
    ->setParameter('customer', $customerId)
    ->getQuery()
    ->setFetchMode(
        'CountryApp\StoreBundle\Entity\Category', 'product', ClassMetadata::FETCH_EAGER
    )
    ->setFetchMode(
        'CountryApp\StoreBundle\Entity\CustomerProductPrice', 'product', ClassMetadata::FETCH_EAGER
    )
    ->getResult(Query::HYDRATE_ARRAY)
;

Пожалуйста, сообщите ваши мысли о том, что может сделать эту работу.Я хочу получить следующую структуру:

[
  0 => [
    Product[
      ..
    ]
    Category[
      ..
    ]
    CustomerProductPrice[
      ..
    ]
  ],
  1 => [
    Product[
      ..
    ]
    Category[
      ..
    ]
    CustomerProductPrice[
      ..
    ]
  ],
..

.
]

1 Ответ

0 голосов
/ 04 марта 2019

При использовании Doctrine вы определяете свои взаимоотношения внутри своей сущности.

Вы можете прочитать больше здесь https://symfony.com/doc/current/doctrine/associations.html всегда читайте документацию и лучшие практики.Я не знаю, используете ли вы Symfony или нет, но это отличный пример и более понятный, чем документы Doctrine.

/**
 * @ORM\Entity()
 */
class Product
{
    // ...

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\Category", inversedBy="products")
     */
    private $category;

    public function getCategory(): ?Category
    {
        return $this->category;
    }

    public function setCategory(?Category $category): self
    {
        $this->category = $category;

        return $this;
    }
}

Как вы видите здесь, вы определяете сущность, которая содержит все ассоциации и свойства.

Обычно ассоциация будет загружаться с отложенной загрузкой по умолчанию, если вы звоните $product->getCategory(), ваша категория загружается с отложенной загрузкой.Если вам не нравится отложенная загрузка, вы всегда можете получить выборку с помощью

/**
 * @ManyToOne(targetEntity="Category", cascade={"all"}, fetch="EAGER")
 */

. И вы получите массив продуктов, в котором каждый продукт будет иметь свойство с именем category и будет содержать сущность Category внутри него.

В этом главное отличие CakePHP, потому что в CakePHP вы получаете все ассоциации отдельно, а в Symfony вы получаете дерево ассоциаций.

И ваши запросы кажутся слишком сложными, и в большинстве случаев у вас нетизменить запросы, как это вообще.Но будьте осторожны с ленивыми загрузками, если вы лениво загружаете данные в огромные списки, у вас будет плохая производительность.

...