如何使用 XML 或 YAML 而非注解映射来定义 Doctrine mappedSuperclass

Posted

技术标签:

【中文标题】如何使用 XML 或 YAML 而非注解映射来定义 Doctrine mappedSuperclass【英文标题】:How to define a Doctrine mappedSuperclass using XML or YAML instead of annotation mapping 【发布时间】:2019-02-05 13:15:56 【问题描述】:

以下脚本来自https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/inheritance-mapping.html#mapped-superclasses,仅更改为包含第二个子类。据我了解,MappedSuperclassBase 不能单独存在,必须由一个且只有一个子类扩展(即EntitySubClassOneEntitySubClassTwo),并且与 SQL 的超类型/子类型概念相同。同意吗?

如何使用 YAML 或 XML 而非注解映射来定义超级/子类型?

<?php
/** @MappedSuperclass */
class MappedSuperclassBase

    /** @Column(type="integer") */
    protected $mapped1;
    /** @Column(type="string") */
    protected $mapped2;
    /**
     * @OneToOne(targetEntity="MappedSuperclassRelated1")
     * @JoinColumn(name="related1_id", referencedColumnName="id")
     */
    protected $mappedRelated1;

    // ... more fields and methods


/** @Entity */
class EntitySubClassOne extends MappedSuperclassBase

    /** @Id @Column(type="integer") */
    private $id;
    /** @Column(type="string") */
    private $name;

    // ... more fields and methods


/** @Entity */
class EntitySubClassTwo extends MappedSuperclassBase

    /** @Id @Column(type="integer") */
    private $id;
    /** @Column(type="string") */
    private $name;

    // ... more fields and methods

【问题讨论】:

在您的链接上,向下滚动到此处:doctrine-project.org/projects/doctrine-orm/en/2.6/reference/… ;-) @rkeet 除非我弄错了,否则该部分仅描述关联覆盖,而有问题的部分被省略并描述为//other fields mapping 您的问题是“如何使用 Yaml / XML”。如果您专门访问该链接,那里的代码示例顶部有选项卡,可让您切换语言。如果您阅读该代码,您会看到“如何”在此处映射请求的MappedSuperClass。 (Yaml:type: mappedSuperclass,XML:&lt;mapped-superclass name="MyProject\Model\User"&gt; @rkeet 但它没有显示 @OneToOne(targetEntity="MappedSuperclassRelated1")@JoinColumn(name="related1_id", referencedColumnName="id") 的等价物,当然,这不是很难转换。更重要的是,它没有解释EntitySubClass 是如何知道它与MappedSuperclassBase 相关联的,而这正是我正在努力的部分。谢谢 如果 Worker 扩展 Person(超类),那么您有 1 个实体:工人。创建与Worker 的关系(即来自Paycheck),仅链接到Worker。超类Person 只是创建了一组用于 Worker 的基本属性/默认值。 【参考方案1】:

根据我们的 cmets,我想我看到了您的困惑。因为the docs 在同一页面上同时处理“MappedSuperclass”和“Discriminator”,所以我认为您已经混淆了它们的用途。希望这可以帮助您:

MappedSuperclass 以可重用的方式提供属性/默认值,但它本身永远不能成为实体。这相当于 PHP 的 abstract 类(不能自行实例化) 鉴别器提供“扩展”实体的能力,使其成为另一个实体。例如,拥有Person 实体会为您提供 1 个实体。此实体可以扩展,例如通过WorkerManager

MappedSuperclass 的一个很好的用例是AbstractEntity。每个实体都需要一个 ID,一个唯一的标识符。它还为您提供了在 Listeners 等中检查的常见内容。所以,继续创建:

/**
 * @ORM\MappedSuperclass
 */
abstract class AbstractEntity

    /**
     * @var int
     * @ORM\Id
     * @ORM\Column(name="id", type="integer", options="unsigned":true)
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    protected $id;
  
    // getter / setter

看看abstractMappedSuperclass 是如何声明的?

这是因为(abstract classMappedSuperclass)都不能自己实例化。你不能做$entity = new AbstractEntity(),因为它是一个abstract PHP 类。 Doctrine 也不会为AbstractEntity 创建单独的表。

接下来,创建一个Person

/**
 * @ORM\Entity
 * @ORM\Table(name="persons")
 *
 * @InheritanceType("JOINED")
 * @DiscriminatorColumn(name="discr", type="string")
 */
class Person extends AbstractEntity

    /**
     * @var string
     * @ORM\Column(name="name", type="string", length=255, nullable=false)
     */
    protected $name;

    // getter / setter

上面的Person,Entity是通过JOINED继承类型为Class Table Inheritance设置的。这意味着,在数据库级别,表 persons 将与其他实体添加的任何列分开,扩展 Person

注意我没有声明DiscriminatorMap。以下来自文档,由我以粗体突出显示:

注意事项:

@InheritanceType、@DiscriminatorColumn 和 @DiscriminatorMap 必须在作为映射实体层次结构一部分的最顶层类中指定。 @DiscriminatorMap 指定鉴别器列的哪些值将行标识为哪种类型。在上面的例子中,“person”值将一行标识为 Person 类型,“employee”将一行标识为 Employee 类型。 如果类与应用了鉴别器映射的实体类包含在同一命名空间中,则鉴别器映射中的类的名称不需要完全限定。 如果没有提供鉴别图,则自动生成图。自动生成的鉴别器映射包含每个类的小写短名称作为键。

现在,让我们创建一个Worker

/**
 * @ORM\Entity
 * @ORM\Table(name="workers")
 */
class Worker extends Person

    /**
     * @var int
     * @ORM\Column(name="worker_id", type="integer", length=11, nullable=false)
     */
    protected $workerId;

    // getter / setter

所以,现在我们有了:

MappedSuperclass:AbstractEntity - 不是独立实体 受歧视:Person - 独立实体 “正常”:Worker - 扩展 Person

注意事项:

MappedSuperclass 无法实例化。因此:您不能创建到它的链接/关系。媲美PHP的abstract class 可识别实体是一个独立的实体,可用作普通实体。您可以毫无问题地与它建立关系 扩展可识别实体的实体是两者的实例。在上面的代码中,这两个都是真的:$worker instanceof Worker$worker instanceof Person,因为Worker 扩展了Person。但是,$person instanceof Worker 将是 false

$workerId = $person-&gt;getWorkerId() // generates "method does not exist" fatal

$workerId = $worker-&gt;getWorkerId() // generates integer value


希望能够为您解决问题。如果没有,请随时询问。

【讨论】:

感谢 rkeet。在您的示例中,您明确定义了class Person extends AbstractEntity。但是如果使用 XML 或 YAML 实现,难道不是从 PHP 类开始,因此无法以这种方式定义这种关系吗? 以这种方式开始,在此处查看前面的链接:doctrine-project.org/projects/doctrine-orm/en/2.6/reference/… - User 是由 Admin 扩展的 MappedSuperclass 的情况。如果你遵循它,你应该能够让它工作。 啊,我明白了我的困惑的根源。我错误地认为 MappedSuperclass 代表 SQL 超类型/子类型 (learndatamodeling.com/blog/supertype-and-subtype)。我知道无法实例化 MappedSuperclass,但我没有意识到没有与之关联的表! 啊,好吧,我没有在答案中解释这一点 ;-) 但同样,这就像 abstract classclass ;-) 因为第一个无法实例化,如一个没有表的实体。后者可以被实例化并且应该有一个关联的数据存储(表)。然后是区分类,其中“单表继承”具有扩展的最父类的“根”表和类表继承,其中每个实体都有自己的表,但连接到其父级(因此它是特定表仅添加其添加的属性)。 再次感谢您的帮助。第一次尝试使用 ORM,这是一段旅程,但开始走到一起。有区别的类是我想要的。

以上是关于如何使用 XML 或 YAML 而非注解映射来定义 Doctrine mappedSuperclass的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate注解

原则 2:有没有办法使用 yaml 或 xml 从 trait 继承映射?

使用注解或使用休眠配置文件休眠

如何将自定义属性添加到 Symfony Doctrine YAML 映射文件

spring boot yaml 自定义配置 映射到 java POJO

MyBaits理解?