2013-10-25 68 views
0

我正在使用遗留数据库(这意味着没有模式更改!),我需要创建所涉及的Doctrine实体之间的关联。我将首先描述数据结构,然后解释我所尝试的。抽象主义关联映射无鉴别器(遗留数据库)

该数据库有一个用户表与其他各种表也存储用户相关的信息。例如:

siteUser有:

  • 内容识别(PK)
  • 的firstName
  • lastName的
  • 用户名
  • 密码
  • ...

siteUser个实体在该系统中它是沿的线的元数据:

  • metadataId(PK)
  • 标题
  • 描述
  • 关键字
  • CREATEDATE
  • publishDate
  • 内容识别
  • contentTable(鉴别器)
  • ...

几乎所有的数据库可以通过存储它在metadata.contentId野外PK,并在metadata.contentTable字段的表名有元数据。请注意,metadata.contentId不是外键,因为我还没有看到它们,所以这些对于DBA来说一定是陌生的。

系统上的用户可以保存他们发现的与他们相关的信息,这样他们可以稍后再回到系统,而不必再去寻找相同的信息。

这与所谓的conLink内容类型,conVideoconLeaflet存储为数据库实体(其中有元数据)来完成。

例如一个conVideo看起来像这样:

  • 内容识别(PK)
  • embedCode

用户可以存储标记这个信息作为与他们相关的方法是由系统存储它在一个叫做userSavedContent的链接表中:

  • userSa vedContentId(PK)
  • 用户id
  • metadataId

注意userSavedContent.userIduserSavedContent.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' 

但是这样做的教义比较复杂,因为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并增加了一个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是一个与该关联。我认为教义本来可以解决这个问题,但显然不是。

所以我的问题是:

  • 是这种做法非常错误的?如果没有,我可以做些什么来使关联/查询工作?

回答

0

解决此问题的方法是让教条热切地获取具体的元数据 - >内容实体。我可以明确地声明它们,但是使用Doctrine的MetadataFactory来获取元数据实体的鉴别器,以获取所有可能的内容类型的列表。

$metadataFactory = $this->getEntityManager()->getMetadataFactory(); 
$metadataMetadata = $metadataFactory->getMetadataFor('MyApp\Bundle\DataApiBundle\Entity\Metadata'); 

foreach ($metadataMetadata->discriminatorMap as $contentEntity) { 
    $builder->getQuery() 
     ->setFetchMode(
      $contentEntity, 
      'content', 
      ClassMetadata::FETCH_EAGER 
     ); 
} 
相关问题