Рассмотрим следующую диаграмму:
Где User
имеет много BlogPost
х, ан Event
это тип BlogPost
со свойством Venue
,
У меня есть следующие классы сущностей:
**
* @ORM\Entity()
* @ORM\Table(name="User")
*/
class User {
...
/**
* @ORM\OneToMany(targetEntity="BlogPost",mappedBy="User")
* @ORM\JoinColumn(...)
*/
protected $BlogPosts;
...
}
/**
* @ORM\Entity()
* @ORM\Table(name="BlogPost")
* @ORM\InheritanceType("JOINED")
* @ORM\DiscriminatorColumn(...)
* @ORM\DiscriminatorMap({...})
* ...
*/
class BlogPost {
...
/**
* @ORM\ManyToOne(targetEntity="User",inversedBy="BlogPosts")
* @ORM\JoinColumn(...)
*/
protected $User
...
}
/**
* @ORM\Entity()
* @ORM\Table(name="Event")
*/
class Event extends BlogPost {
...
/**
* @ORM\ManyToOne(targetEntity="Venue")
* @ORM\JoinColumn(...)
*/
protected $Venue;
...
}
/**
* @ORM\Entity()
* @ORM\Table(name="Venue")
*/
class Venue {
...
}
Теперь я хотел бы создать запрос, который получает события определенных пользователей и активно загружает места событий. Самое близкое, что у меня есть:
$qb = $em->createQueryBuilder();
$qb
->select('User,'BlogPost,Venue')
->from('User','User')
->join('User.BlogPosts','BlogPost','WITH','BlogPost INSTANCE OF :Event')
->join('BlogPost.Venue','Venue')
->setParameter('Event',$em->getClassMetadata('Event'));
Это дает мне довольно предсказуемую ошибку:
Error: Class BlogPost has no association named Venue
Удаление ссылок на Venue
Я получу всех пользователей Event
Это просто отлично, но тогда мне придется положиться на ленивую загрузку, чтобы получить остальную часть Event
свойства.
Я видел предложения, которые я сопоставляю Events
в User
:
class User {
...
/**
* @ORM\OneToMany(targetEntity="BlogPost",mappedBy="User")
* @ORM\JoinColumn(name="UserID", referenceColumnName="UserID")
*/
protected $BlogPosts;
/**
* @ORM\OneToMany(targetEntity="Event",mappedBy="User")
* @ORM\JoinColumn(name="UserID", referenceColumnName="UserID")
*/
protected $Events;
...
}
При попытке этого генерируемый SQL пытается сделать что-то вроде:
SELECT * FROM User
JOIN Event ON User.id = Event.user_id
JOIN BlogPost ON BlogPost.id = Event.blog_post_id
куда user_id
столбец в BlogPost
и не Event
и, следовательно, ошибки с:
Invalid column name 'user_id'
Как я должен отображать таблицы классов наследуемых ссылок?
Есть ли способ добиться полной загрузки, как я описал?
Мне известно, что я упустил некоторые детали из классов, их отображения и сгенерированного SQL. Пожалуйста, кричите, если некоторые детали помогут разобраться в этом.
редактировать
Это отличается от Наследование в одной таблице (STI) с отношением ManyToOne как для наследования таблиц классов, а не наследования таблиц. Кроме того, меня интересует специфика свойств подкласса, представьте, если в этом примере Video
были дополнительные ссылки.
Я нашел способ, который делает то, что я хочу, но я уверен, что должен быть лучший путь.
Сначала напишите собственный запрос:
$sql =<<<SQL
SELECT * FROM User user
JOIN BlogPost blog_post ON user.id = blog_post.UserID
JOIN Event event ON blog_post.id = event.BlogPostID
JOIN Venue venue ON event.VenueID = venue.id
WHERE user.id = ?
SQL;
Это можно либо запустить напрямую через $em->getConnection()->prepare()
или еще лучше, используя ResultSetMapping, а затем через $em->createNativeQuery($sql,$rsm)
$rsm = new \Doctrine\ORM\Query\ResultSetMappingBuilder($em);
$rsm->addRootEntityFromClassMetadata('User','user');
$rsm->addIndexBy('user','id');
$rsm->addJoinedEntityResult('event','event','user','BlogPosts');
$rsm->addJoinedEntityResult('venue','venue','event','Venue');
$rsm->addFieldResult(); // add all of the fields you are interested in
$query = $this->get_manager()->createNativeQuery($sql,$rsm);
$query->setParameter(1, $user_id);
return $query->getResult($hydration_mode);
Кажется позором, что это не может быть сделано через QueryBuilder
но, насколько я могу судить, это единственный способ достичь этого. Я хотел бы, чтобы меня показали иначе.
Других решений пока нет …