私はレガシー データベースを使用しており (つまり、スキーマの変更はありません!)、関連する Doctrine エンティティ間の関連付けを作成する必要があります。最初にデータ構造について説明し、次に何を試したかを説明します。
データベースには、ユーザー関連の情報を格納する他のさまざまなテーブルを含むユーザー テーブルがあります。例えば:
siteUser
もっている:
- コンテンツ ID (PK)
- ファーストネーム
- 苗字
- ユーザー名
- パスワード
- ...
およびsiteUser
エンティティは、このシステムに次のようなメタデータを持っています。
- メタデータ ID (PK)
- 題名
- 説明
- キーワード
- 日付を作成します
- 公開日
- contentId
- contentTable (識別子)
- ...
データベース内のほとんどすべてのものは、PK をmetadata.contentId
フィールドに格納し、テーブル名をフィールドに格納することにより、メタデータを持つことができmetadata.contentTable
ます。は外部キーではないことに注意してくださいmetadata.contentId
。これらは DBA にとって異質なものだったに違いありません。
システム上のユーザーは、自分に関連する情報を保存できるため、後でシステムに戻って同じ情報を探し回る必要がなくなります。
これは、データベース エンティティ (メタデータを持つ) として格納されているconLink
、conVideo
と呼ばれるコンテンツ タイプで行われます。conLeaflet
たとえば、conVideo
次のようになります。
- コンテンツ ID (PK)
- 埋め込みコード
ユーザーがこの情報を自分に関連するものとしてマークして保存する方法は、システムがそれを と呼ばれるリンク テーブルに保存することですuserSavedContent
。
- userSavedContentId (PK)
- ユーザーID
- メタデータ 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
持っていないので、これはもちろん理にかなっています。その子はその関連付けを持つものです。私は Doctrine がこれを解決できると思っていましたが、明らかにそうではありませんでした。content
MyApp\Bundle\DataApiBundle\Entity\Metadata\ConVideoMetadata
だから私の質問は:
- このアプローチは非常に間違っていますか? そうでない場合、その関連付け/クエリを機能させるために何ができますか?