Doctrine 2.2 ORM:查找扩展实体
Posted
技术标签:
【中文标题】Doctrine 2.2 ORM:查找扩展实体【英文标题】:Doctrine 2.2 ORM: find extended entity 【发布时间】:2014-03-05 16:00:41 【问题描述】:我应该如何注释继承才能找到子类? 我当前的注释:
<?php
// Product.php
namespace Entity;
/**
* @Entity @Table(name="products")
**/
class Product
/**
* @var int
* @Id @Column(type="integer") @GeneratedValue
*/
protected $id;
<?php
namespace Entity;
// Coffee.php
/**
* @Entity
*/
class Coffee extends Product
protected $taste;
当我坚持新实体但无法通过 Id 获取现有实体时,它就像一个魅力
$entityManager->find('Entity\\Coffee', 1)
有错误:
找不到列:1054 'where 子句'中的未知列't0.id'
我不能将MappedSuperclass 用于产品。
更新:
Product::taste
不是数据库列。这是一个POPO字段。我必须将自己与 Doctrine ORM 继承混淆,后者旨在扩展模型以保留扩展实体的额外数据。在我的情况下,子类没有额外的列,而是定义了基类的不同行为。此外,两者都是可以互换的,所以我希望
$coffee = new Entity\Coffee();
$entityManager->persist($coffee);
$entityManager->flush();
/* @var Entity\Product $product */
$product = $entityManager->find('Entity\\Product', $coffee->getId());
/* @var Entity\Coffee $coffee */
$coffee = $entityManager->find('Entity\\Coffee', $product->getId());
看来我真的不需要 ORM 继承,而只是将 products
表中的数据水合到基础对象或子对象中。但不确定是否可能。
【问题讨论】:
只需将带有正确注释的受保护ID添加到子类中...没有注释学说就无法调用存储库上的find方法。 单表继承对你有用吗? docs.doctrine-project.org/projects/doctrine-orm/en/latest/… @Rufinus 谢谢,但这无济于事。 AFAIK AnnotationDriver 从父类获取注释,我的问题在于元数据工厂。它为子类创建1个别名't0'并在where
子句中使用它,然后创建另一个别名't1'并在from
子句中使用。
@bspellmeyer 这是一个单表。我尝试显式添加@InheritanceType("SINGLE_TABLE")
,但没有任何效果。不确定鉴别器是否可以解决问题,但如果可能的话,我想避免在数据库中使用无意义的列。
【参考方案1】:
您需要在超类上提供 InheritanceType、DiscriminatorMap 和 DiscriminatorColumn 才能正确映射继承关系。它将向表中添加一个额外的列(您在 DiscriminatorColumn 中指定的列)。
【讨论】:
我已更新我的问题以避免进一步混淆。如果我使用@DiscriminatorMap("anything" = "Product", "anything" = "Coffee")
我无法持久化产品,如果我使用@DiscriminatorMap("product" = "Product", "coffee" = "Coffee")
它在我尝试获取$entityManager->find('Entity\\Product', $coffee->getId());
时返回Coffee
对象
根据您的更新,我对您真正想要做什么感到困惑。但无论哪种方式,只要使用所有三个鉴别器,你就会得到你想要的,我想。
是的,我必须承认这令人困惑。鉴别器的问题是鉴别器列中的值定义了结果对象的类。
这是怎么回事? Doctrine 需要知道表中的第 123 行是否应该作为咖啡产品进行水合。如果没有鉴别器列,Doctrine 将无法始终如一地分辨出差异。
我需要从应用程序而不是数据库控制它。 Doctrine 知道来自$entityManager->find(name, id)
的实体名称和 ID,这应该足以获取一行并将其合并到请求的类中。我不控制它运行时的鉴别器的问题。由于对象以Coffee
的形式存在,因此它不能水合为Product
。问题中的最后一个代码示例不适用于鉴别器。 $product
是 Coffee
的一个实例,这不是我所期望的。【参考方案2】:
到目前为止我发现的一个临时解决方法是使用@bspellmeyer 和@timdev 建议的单表继承和dynamic mapping:
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
use Doctrine\ORM\Mapping\ClassMetadata;
class ProductEntityListener
public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
$metadata = $eventArgs->getClassMetadata();
if (in_array($metadata->getName(), [
'Entity\Coffee',
'Entity\Product'
]))
$metadata->setInheritanceType(ClassMetadata::INHERITANCE_TYPE_SINGLE_TABLE);
$metadata->setDiscriminatorColumn(['name' => 'discr', 'type' => 'string', 'length' => 3]);
$metadata->addDiscriminatorMapClass('all', $metadata->getName());
$metadata->subClasses = [];
虽然它完成了这项工作,但我并没有将其标记为正确答案,因为它仍然需要一个额外的无意义列 discr
,其中包含所有行的“全部”,而且是相当黑客。我想知道是否有适当的解决方案来扩展实体类而不扩展 ORM 模型。
【讨论】:
这篇文章中的动态映射链接已经失效。新链接是doctrine-project.org/projects/doctrine-orm/en/current/reference/…以上是关于Doctrine 2.2 ORM:查找扩展实体的主要内容,如果未能解决你的问题,请参考以下文章
ZF2 Skeleton 和 Doctrine ORM xml 模式合并
如何在 Doctrine ORM 查询中查找与别名相关的表?