首页 > 解决方案 > Symfony Doctrine oneToMany 逆数组键

问题描述

(抱歉标题混乱,我很难用一句话解释清楚!)

我基本上有 3 个相互连接的实体SlideshowSlideSlideshowContentLanguage. SlideshowContent具有以下要链接到的属性SlideshowSlide

/**
 * @ORM\ManyToOne(targetEntity="App\Entity\SlideshowSlide", inversedBy="content", fetch="EAGER")
 * @ORM\JoinColumn(referencedColumnName="id", nullable=false)
 */
private $slide;

以及将其链接到的以下属性Language

/**
 * @ORM\ManyToOne(targetEntity="App\Entity\Language", fetch="EAGER")
 * @ORM\JoinColumn(nullable=false)
 */
private $language;

在我的SlideshowSlide我有以下content属性:

/**
 * @ORM\OneToMany(targetEntity="App\Entity\SlideshowContent", mappedBy="slide", fetch="EAGER")
 */
private $content;

问题是,我知道我可以获取SlideshowContenta 中的所有实例SlideshowSlide,转储类似于:

array:1 [▼
  0 => SlideshowSlide {#1052 ▼
    -id: 1
    -image: null
    -imageAlt: null
    -url: null
    -owner: Domain {#736 ▶}
    -content: PersistentCollection {#1077 ▼
      -snapshot: array:1 [ …1]
      -owner: SlideshowSlide {#1052}
      -association: array:16 [ …16]
      -em: EntityManager {#381 …11}
      -backRefFieldName: "slide"
      -typeClass: ClassMetadata {#929 …}
      -isDirty: false
      #collection: ArrayCollection {#1050 ▼
        -elements: array:1 [▼
          0 => SlideshowContent {#1094 ▼
            -id: 1
            -slide: SlideshowSlide {#1052}
            -language: Language {#1039 ▶}
            -title: "test"
            -content: "test2"
          }
        ]
      }
      #initialized: true
    }
  }
]

#collection数组有一个带有从零开始的索引键的数组。但是,我不想使用idlanguage作为我的键,我该如何实现呢?

标签: symfonydoctrine

解决方案


我刚刚测试了indexed associations,我认为它确实符合您的要求。
这是我的代码和生成的转储:

class A
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @var B
     * @ORM\ManyToOne(targetEntity="App\Entity\B", inversedBy="as")
     * @ORM\JoinColumn(name="b_id", referencedColumnName="id", nullable=false)
     */
    private $b;

    /**
     * @var C
     * @ORM\ManyToOne(targetEntity="App\Entity\C", fetch="EAGER")
     * @ORM\JoinColumn(name="c_id", referencedColumnName="id", nullable=false)
     */
    private $c;
//...
class B
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @var ArrayCollection<A>
     * @ORM\OneToMany(targetEntity="App\Entity\A", mappedBy="b", fetch="EAGER", indexBy="c_id")
     */
    private $as;
//...

注意关联indexBy上的选项。@OneToMany

class C
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

}

数据:

Table A
╔════╦══════╦══════╗
║ id ║ b_id ║ c_id ║
╠════╬══════╬══════╣
║ 34 ║   12 ║    2 ║
║ 35 ║   12 ║    5 ║
║ 36 ║   12 ║    6 ║
║ 37 ║   12 ║    1 ║
║ 38 ║   12 ║    5 ║
╚════╩══════╩══════╝

转储 B 的实例id = 12

B {#691 ▼
  -id: 12
  -as: PersistentCollection {#641 ▼
// ...irrelevant metadata...
    #collection: ArrayCollection {#584 ▼
      -elements: array:4 [▼
        2 => A {#552 ▼
          -id: 34
          -b: B {#586}
          -c: C {#542 ▼
            +__isInitialized__: true
            -id: 2
             …2
          }
        }
        5 => A {#541 ▼
          -id: 38
          -b: B {#586}
          -c: C {#540 ▼
            +__isInitialized__: true
            -id: 5
             …2
          }
        }
        6 => A {#539 ▶}
        1 => A {#537 ▶}
      ]

没有indexBy

B {#566 ▼
  -id: 12
  -as: PersistentCollection {#516 ▼
// ...irrelevant metadata...
    #collection: ArrayCollection {#584 ▼
      -elements: array:5 [▼
        0 => A {#552 ▼
          -id: 34
          -b: B {#586}
          -c: C {#542 ▼
            +__isInitialized__: true
            -id: 2
             …2
          }
        }
        1 => A {#541 ▼
          -id: 35
          -b: B {#586}
          -c: C {#540 ▼
            +__isInitialized__: true
            -id: 5
             …2
          }
        }
        2 => A {#539 ▶}
        3 => A {#537 ▶}
        4 => A {#523 ▶}
      ]

请注意此功能的记录缺点:

  • 如果要按字段值更改索引,则必须同时管理键和字段。
  • 在每个请求中,键都是从字段值中重新生成的,而不是从之前的集合键中重新生成的。
  • 在持久化期间从不考虑 Index-By 键的值。它们仅用于访问目的。
  • 用于按特征索引的字段在数据库中必须是唯一的。具有相同索引字段值的多个实体的行为未定义。

我必须强调最后一点:在我的测试中,使用非唯一值作为索引会导致 Doctrine 仅加载该键的最后一个对象。在我的示例中,id 为 35 的对象 A 在c_id用作索引时被丢弃。


推荐阅读