我的问题是,我无法在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来完成此操作。
我是否需要为父表设置“类型”列,以便每行定义它是部件,模型还是选项?
答案 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
是将每个键映射到实体的方式。你说你有以下
然后,你的鉴别器地图应该是这样的,例如:
@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)
,你会发现一些有趣的东西。该对象将是Model
,Part
或Option
的实例,因为这些实体中的每一个都在您的鉴别器映射中定义,并且Doctrine会根据该映射自动映射您的记录。
之后,在这种情况下,这可以派上用场:
if( $product instanceof \AppBundle\Entity\Part ) {
// do something only if that record belongs to part.
}