До сих пор я пробовал следующее, но я продолжаю получать только основную информацию об объекте, присоединенные объекты не доходят до результата:
Вариант 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[
..
]
],
..
.
]
Я получаю только Product, дети или Customer и CustomerProductPrice не заполнены.
@eiiCreative не могли бы вы объяснить проблему, которую пытаетесь решить?
@vytsci По сути, я пытаюсь вернуть массив результатов за один вызов SQL, чтобы избежать прыжков туда и обратно на сервер. В cakephp я делаю это с помощью содержимого, которое гарантирует, что мои данные уже есть в результате. Просто кажется, что я не могу найти способ сделать это в доктрине. Я знаю, что мог бы изменить аннотации, чтобы сделать его нетерпеливым, а не ленивым, но это повлияет на каждое использование объекта, а не только на этот вариант использования.
О, вы из CakePHP: D Тогда я отвечу.




При использовании 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")
*/
И вы получите массив продуктов, где каждый продукт будет иметь свойство с именем категория и будет содержать сущность категории внутри него.
В этом главное отличие CakePHP, потому что в CakePHP вы получаете все ассоциации отдельно, а в Symfony вы получаете дерево ассоциаций.
И ваши запросы кажутся слишком сложными, и в большинстве случаев вам вообще не нужно модифицировать такие запросы. Но будьте осторожны с ленивой загрузкой, если вы лениво загружаете данные в огромные списки, вы получите низкую производительность.
спасибо @vytsci В итоге я выбрал настройку EAGER для выборки в классе сущности клиента, поскольку мне нужна только CustomerProductPrice при запросе клиента, и я запрашиваю клиента намного меньше, чем я запрашиваю продукт. Было бы неплохо увидеть, действительно ли fetchMode может быть изменен adhoc для каждого запроса, особенно в случае запросов отчетов. К сожалению, мои попытки пока не сработали.
Ну можно stackoverflow.com/questions/6939339/… но официальная документация по доктрине не работает, а где-то в комментариях прописан синтаксис. Проверь это.
Понял, я должен явно назвать поля, которые мне нужны, я скоро обновлю здесь, спасибо @vytsci
@eiiCreative нп
Вы не возвращаете данные или они просто не в ожидаемом формате? Поскольку ваше сопоставление предполагает, вы должны получить Product и внутри этого объекта существуют Category и CustomerProductPrice. Таким образом, объединенные объекты являются дочерними элементами, а не братьями и сестрами продукта. Это ожидаемое поведение. Но позже вы можете сопоставить полученный список продуктов со структурой массива.