在 Doctrine 中将一对多映射到 "joined" 子 class 时,如何消除模式验证错误?

How do I get rid of schema validation errors when mapping one-to-many to a "joined" child class in Doctrine?

我有一个抽象 ContentItem class,它是一个具有继承类型 JOINED 的 Doctrine 实体。它与 BusinessAccount 实体处于多对一关系。 BusinessAccountContentItem 的非抽象子 class 具有一对多关系,特别是 TextItem,它们与上述多对一关系相反.

这是代码:(删除了不相关的部分)

/**
 * @ORM\Entity
 * @ORM\InheritanceType("JOINED")
 */
abstract class ContentItem
{
    /**
     * @var BusinessAccount
     * @ORM\ManyToOne(targetEntity=BusinessAccount::class)
     */
    protected $businessAccount;
}

/*
 * @ORM\Entity
 */
class BusinessAccount
{
    /**
     * @var Collection<TextItem>
     * @ORM\OneToMany(targetEntity=TextItem::class, mappedBy="businessAccount")
     */
    private $textItems;
}

/*
 * @ORM\Entity
 */
class TextItem extends ContentItem
{
    // nothing interesting here
}

想法是保证每个 ContentItem 个子 class 属于一个 BusinessAccount,同时将不同的子分离到 BusinessAccount 上的单独 replationships边.

这段代码工作得很好,但是它没有通过 Doctrine 的 doctrine:schema:validate 命令的模式验证:

Mapping

[FAIL] The entity-class App\Application\BusinessAccount mapping is invalid:

  • The field App\Application\BusinessAccount#textItems is on the inverse side of a bi-directional relationship, but the specified mappedBy association on the target-entity App\Entity\TextItem#businessAccount does not contain the required 'inversedBy="textItems"' attribute.

在我看来,Doctrine 正确地将 many-to-oneone-to-many 识别为一个关联的两个方面,但它希望我在 [= 上明确指定反向 属性 的名称25=]。我不能这样做,因为有多个逆属性,每个子 class of ContentItem.

我可以通过将 $businessAccount 属性 移动到 ContentItem 的子 class 来消除这些错误。我不觉得这个解决方案令人满意,因为它引入了代码重复,很难保证每个 ContentItem 子类型的所有权并将外键移动到其他表。

我试图用指定的 inversedBy 覆盖子 class 中的 $businessAccount 属性,但这并没有使错误消失。

是否有一个干净的解决方案可以让我解决这些错误?

我想你可以用 Association Overrides 来做到这一点。

基本上你在父实体中有一个正确和完整的映射(例如包括 inversed_by 属性):

/**
 * @ORM\Entity
 * @ORM\InheritanceType("JOINED")
 */
abstract class ContentItem
{
    /**
     * @var BusinessAccount
     * @ORM\ManyToOne(targetEntity=BusinessAccount::class, inversedBy="textItems")
     */
    protected $businessAccount;
}

然后在需要时在子项中定义特定的覆盖:

/*
 * @ORM\Entity
 * @ORM\AssociationOverrides({
 *      @ORM\AssociationOverride(name="businessAccount",
 *          inversedBy="otherProperty"
 *      )
 * })
 */
class TextItem extends ContentItem
{
    // nothing interesting here
}