如何在Symfony中设置Doctrine的类继承?

时间:2015-05-01 18:29:54

标签: symfony doctrine

我的问题是,我无法在Doctrine的类继承中掌握DiscriminatorColumn和DiscriminatorMap。

我有一个被视为父类/表的产品实体。

有几个子实体继承了产品实体。 (型号,零件和选项)

我觉得我应该能够使用主键链接两个表......但是我如何使用DiscriminatorColumn呢?

以下是我想要发生的事情的一般概念......

  

在继承产品父实体

的同时从数据库中获取所有模型对象
SELECT object 
FROM parts_object parts
LEFT JOIN products_object po
ON parts.product_fk = po.product_id
  

或者......在继承产品父实体

的同时从数据库中获取所有部分对象
SELECT object 
FROM parts_object parts
LEFT JOIN products_object po
ON parts.product_fk = po.product_id

理想情况下,我希望使用Doctrine而不是某些自定义SQL来完成此操作。

我是否需要为父表设置“类型”列,以便每行定义它是部件,模型还是选项?

Doctrine inheritance docs

2 个答案:

答案 0 :(得分:4)

如果你想使用DiscriminatorMap for Doctrine,那么你应该使用Doctrine,而不是SQL。

基本设置是:

/**
 * @ORM\Table(name="product")
 * @ORM\Entity(repositoryClass="MyApp\ProductBundle\Repository\ProductRepository")
 * @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\DiscriminatorColumn(name="productType", type="string")
 * @ORM\DiscriminatorMap({
 *   "Product" = "Product",
 *   "Model" = "Model",
 *   "Part" = "Part",
 *   "Option" = "Option",
 * })
 */
class Product
{
...
}

MyApp的\ ProductBundle \实体\模型

/**
 * @ORM\Entity(repositoryClass="MyApp\ProductBundle\Repository\ModelRepository")
 */
class Model extends Product 
{
}

MyApp的\ ProductBundle \实体\部分

/**
 * @ORM\Entity(repositoryClass="MyApp\ProductBundle\Repository\PartRepository")
 */
class Part extends Product 
{
}

MyApp的\ ProductBundle \实体\选项

/**
 * @ORM\Entity(repositoryClass="MyApp\ProductBundle\Repository\OptionRepository")
 */
class Option extends Product 
{
}

然后,如果您需要获得控制器上的所有产品

 $em = $this->getDoctrine()->getManager(); 
 $repo = $em->getRepository("MyAppProductBundle:Product");
 $products = $repo->findAll();

然后,如果您需要选择所有模型,只需设置正确的存储库

 $repo = $em->getRepository("MyAppProductBundle:Model");
 $models = $repo->findAll();

答案 1 :(得分:2)

好的,我会尽量解释这个。

让我们从DiscriminatorColumn

开始

Discriminator列基本上就像数据库中的一列一样。它用于存储密钥,如果您愿意,可以根据您的DiscriminatorMap配置确定您当前查询的对象类型。

DiscriminatorMap是将每个映射到实体的方式。你说你有以下

  • 产品[parent]
  • 模型[父母的孩子]
  • 部分[父母的孩子]
  • 选项[父母的孩子]

然后,你的鉴别器地图应该是这样的,例如:

@DiscriminatorMap({
    "model" = "AppBundle\Entity\Model", 
    "Part" = "AppBundle\Entity\Part",
    "Option" = "AppBundle\Entity\Option"
})
  

始终注意映射中的最后一个定义。最后一行必须以逗号结束!

InheritanceType开始,我建议您使用@InheritanceType("JOINED"),因为这样您就可以为每个子课程设置单个表格。

每个子类都必须扩展您的Product实体类,这显然是父类。由于继承映射,每个子类都不能定义$id属性。

然后按特定类型查询记录,并附带以下查询:

"SELECT product FROM AppBundle\Entity\Product product WHERE product INSTANCE OF AppBundle\Entity\Part"

查询将仅搜索映射到此实体的记录。

如果您有任何疑问,请随时提出。

编辑新评论

-----------------------

多一点解释。您不需要在实体映射中创建任何额外的属性/列。添加此注释@DiscriminatorColumn(name="discr", type="string")原则的那一刻将自动为您创建该列。此示例中的列将命名为discr,类型为VARCHAR

  

我仍然不明白用于连接表的内容。如何将学说知道链接产品和模型之间的ID

关于这部分。如果您使用@InheritanceType("JOINED"),则表示您的GeneratedValue ID将在您的主要实体中设置 - Product。然后,扩展Product的每个子实体将自动获得相同的ID,这就是您不需要在子实体中指定$id属性的原因。

最后,如何查看当前正在查看的实体类型。考虑以下场景,每个子实体都扩展Product,我们将对记录执行虚拟搜索:

$product = $entityManager->find('AppBundle:Product', 1); // example

现在,如果你真的去做var_dump($product),你会发现一些有趣的东西。该对象将是ModelPartOption的实例,因为这些实体中的每一个都在您的鉴别器映射中定义,并且Doctrine会根据该映射自动映射您的记录。 之后,在这种情况下,这可以派上用场:

if( $product instanceof \AppBundle\Entity\Part ) {
    // do something only if that record belongs to part.
}