我正在使用旧数据库(这意味着没有架构更改!),我需要在所涉及的 Doctrine 实体之间创建关联。我将首先描述数据结构,然后解释我尝试过的内容。
该数据库有一个用户表和各种其他表,这些表也存储用户相关信息。例如:
siteUser
有:
- 内容 ID (PK)
- 名
- 姓
- 用户名
- 密码
- ...
和siteUser
实体在这个系统中有元数据,这些元数据是:
- 元数据 ID (PK)
- 标题
- 描述
- 关键词
- 创建日期
- 发布日期
- 内容标识
- 内容表(鉴别器)
- ...
几乎数据库中的所有内容都可以通过将其 PK 存储在metadata.contentId
字段中并将表名存储在字段中来具有元数据metadata.contentTable
。请注意,这metadata.contentId
不是外键,这些对 DBA 来说一定是陌生的,因为我还没有看到一个。
系统上的用户可以保存他们发现与他们相关的信息,以便他们以后可以回到系统,而不必再次寻找相同的信息。
这是通过存储为数据库实体(具有元数据)的名为conLink
,conVideo
的内容类型来完成的。conLeaflet
例如一个conVideo
看起来像这样:
- 内容 ID (PK)
- 嵌入代码
用户可以将此信息标记为与他们相关的存储方式是系统将其存储在名为的链接表中userSavedContent
:
- userSavedContentId (PK)
- 用户身份
- 元数据Id
请注意,userSavedContent.userId
anduserSavedContent.metadataId
也不是外键约束。
该方法!
我需要获取用户保存的内容。在 SQL 中这没问题!
SELECT
metadata.title,
conVideo.embedCode
FROM
userSavedContent
INNER JOIN
metadata ON userSavedContent.metadataId = metadata.metadataId
INNER JOIN
conVideo ON conVideo.contentId = metadata.contentId
WHERE userSavedContent.userId = 193745
AND metadata.contentTable = 'conVideo'
然而,在 Doctrine 中这样做更复杂,因为 的值metadata.contentTable
可能是任何conLink
, conVideo
,conLeaflet
实体。
所以我的应用程序是使用 Symfony2(和 Doctrine)构建的,并且我为所有上述实体定义了模型。
这Metadata
是一个带有鉴别器的抽象类metadata.contentTable
:
/**
*
* @ORM\Table(name="metadata")
* @ORM\Entity()
* @ORM\HasLifecycleCallbacks
* @ORM\InheritanceType("SINGLE_TABLE")
* @ORM\DiscriminatorColumn(name="contentTable", type="string")
* @ORM\DiscriminatorMap(
* {
* "conLink" = "MyApp\Bundle\DataApiBundle\Entity\Metadata\ConLinkMetadata",
* "conVideo" = "MyApp\Bundle\DataApiBundle\Entity\Metadata\ConVideoMetadata",
* "siteUser" = "MyApp\Bundle\DataApiBundle\Entity\Metadata\SiteUserMetadata"
* }
* )
*/
abstract class Metadata
该类ConVideoMetadata
扩展Metadata
并添加了一个将实体content
与其关联的属性:ConVideo
/**
* @var ContentType $content
*
* @ORM\OneToOne(
* targetEntity="MyApp\Bundle\DataApiBundle\Entity\ContentType\ConVideo",
* inversedBy="metadata",
* cascade={"persist", "remove"}
* )
* @ORM\JoinColumn(name="contentId", referencedColumnName="contentId")
*/
protected $content;
现在userSavedContent
实体具有metadata
将其关联到元数据项的属性。
/**
* @var Metadata $metadata
*
* @ORM\ManyToOne(
* targetEntity="MyApp\Bundle\DataApiBundle\Entity\Metadata",
* inversedBy="userSavedContent"
* )
* @ORM\JoinColumn(name="id", referencedColumnName="metadataId")
*/
protected $metadata;
最后,siteUser
它与userSavedContent
它的实体上的以下属性相关:
/**
* @ORM\OneToMany(
* targetEntity="MyApp\Bundle\DataApiBundle\Entity\UserSavedContent",
* mappedBy="siteUser",
* cascade={"persist", "remove"},
* orphanRemoval=true
* )
* @ORM\JoinColumn(name="contentId", referencedColumnName="userId")
*/
private $userSavedContentItems;
问题!
在我的siteUserRepository
课堂上,我现在需要查询一个 siteUser 及其所有保存的内容项:
$builder = $this->createQueryBuilder('s')
->select('s', 'm', 'usc', 'uscm', 'uscc')
->innerJoin('s.metadata', 'm')
->leftJoin('s.userSavedContentItems', 'usc')
->leftJoin('usc.metadata', 'uscm')
->leftJoin('uscm.content', 'uscc');
return $builder;
这不行!
"[Semantical Error] Error: Class MyApp\Bundle\DataApiBundle\Entity\Metadata has no association named content"
这当然是有道理的,因为MyApp\Bundle\DataApiBundle\Entity\Metadata
没有这个content
属性,它的孩子MyApp\Bundle\DataApiBundle\Entity\Metadata\ConVideoMetadata
就是那个关联的那个。我认为 Doctrine 可以解决这个问题,但显然不是。
所以我的问题是:
- 这种做法是不是很错误?如果不是,我该怎么做才能使该关联/查询起作用?