0

私はレガシー データベースを使用しており (つまり、スキーマの変更はありません!)、関連する Doctrine エンティティ間の関連付けを作成する必要があります。最初にデータ構造について説明し、次に何を試したかを説明します。

データベースには、ユーザー関連の情報を格納する他のさまざまなテーブルを含むユーザー テーブルがあります。例えば:

siteUserもっている:

  • コンテンツ ID (PK)
  • ファーストネーム
  • 苗字
  • ユーザー名
  • パスワード
  • ...

およびsiteUserエンティティは、このシステムに次のようなメタデータを持っています。

  • メタデータ ID (PK)
  • 題名
  • 説明
  • キーワード
  • 日付を作成します
  • 公開日
  • contentId
  • contentTable (識別子)
  • ...

データベース内のほとんどすべてのものは、PK をmetadata.contentIdフィールドに格納し、テーブル名をフィールドに格納することにより、メタデータを持つことができmetadata.contentTableます。は外部キーではないことに注意してくださいmetadata.contentId。これらは DBA にとって異質なものだったに違いありません。

システム上のユーザーは、自分に関連する情報を保存できるため、後でシステムに戻って同じ情報を探し回る必要がなくなります。

これは、データベース エンティティ (メタデータを持つ) として格納されているconLinkconVideoと呼ばれるコンテンツ タイプで行われます。conLeaflet

たとえば、conVideo次のようになります。

  • コンテンツ ID (PK)
  • 埋め込みコード

ユーザーがこの情報を自分に関連するものとしてマークして保存する方法は、システムがそれを と呼ばれるリンク テーブルに保存することですuserSavedContent

  • userSavedContentId (PK)
  • ユーザーID
  • メタデータ ID

userSavedContent.userIdanduserSavedContent.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のいずれかになる可能性があるからです。conLinkconVideoconLeaflet

したがって、私のアプリケーションは 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して追加します。contentConVideo

/**
 * @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 がこれを解決できると思っていましたが、明らかにそうではありませんでした。contentMyApp\Bundle\DataApiBundle\Entity\Metadata\ConVideoMetadata

だから私の質問は:

  • このアプローチは非常に間違っていますか? そうでない場合、その関連付け/クエリを機能させるために何ができますか?
4

1 に答える 1