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-&gt;find('Entity\\Product', $coffee-&gt;getId()); 时返回Coffee 对象 根据您的更新,我对您真正想要做什么感到困惑。但无论哪种方式,只要使用所有三个鉴别器,你就会得到你想要的,我想。 是的,我必须承认这令人困惑。鉴别器的问题是鉴别器列中的值定义了结果对象的类。 这是怎么回事? Doctrine 需要知道表中的第 123 行是否应该作为咖啡产品进行水合。如果没有鉴别器列,Doctrine 将无法始终如一地分辨出差异。 我需要从应用程序而不是数据库控制它。 Doctrine 知道来自$entityManager-&gt;find(name, id) 的实体名称和 ID,这应该足以获取一行并将其合并到请求的类中。我不控制它运行时的鉴别器的问题。由于对象以Coffee 的形式存在,因此它不能水合为Product。问题中的最后一个代码示例不适用于鉴别器。 $productCoffee 的一个实例,这不是我所期望的。【参考方案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:查找扩展实体的主要内容,如果未能解决你的问题,请参考以下文章

Doctrine 2 WHERE IN 子句使用实体集合

ZF2 Skeleton 和 Doctrine ORM xml 模式合并

如何在 Doctrine ORM 查询中查找与别名相关的表?

Doctrine 2 ORM 级联删除相关实体

Doctrine 2.2 ORM:从数据库进行逆向工程后抛出 MappingException

从 orm.xml Doctrine 生成 php 实体