考虑下图:
哪里有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 {
...
}
我现在想构建一个查询来获取给定的用户事件并急切地加载事件 field 。我得到的最接近的是:
$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 中省略了大量细节。如果某些细节有助于深入了解这一点,请大喊大叫。
编辑
这不同于 Single Table Inheritance (STI) with a ManyToOne relationship作为它的类表继承而不是单表继承。此外,我对子类的属性细节感兴趣,想象一下,如果在那个例子中,
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
来完成,这似乎很遗憾。但据我所知,这是实现这一目标的唯一方法。我很乐意以其他方式展示。
关于php - Doctrine 类表继承 - 热切加载子类引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34614353/