对于实体之间的 OneToMany 关系,如何使用 Doctrine 创建正确的 queryBuilder(在 Inversed Side 实体上)

With a OneToMany relation between entities, how create the right queryBuilder with Doctrine (on the Inversed Side entity)

我的 symfony2.6 项目中有这 3 个 实体

Compteurs.php

class Compteurs
{
    /**
     * @var \PointsComptage
     *
     * @ORM\ManyToOne(targetEntity="PointsComptage", inversedBy="compteurs")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="pointscomptage_id", referencedColumnName="id")
     * })
     */
    private $pointsComptage;

    /**
     * @var \Doctrine\Common\Collections\Collection
     *
     * @ORM\OneToMany(targetEntity="ParametresMesure", mappedBy="compteurs")
     */
    private $parametresMesure;

ParametresMesure.php:

class ParametresMesure
{
    /**
     * @var Compteurs
     *
     * @ORM\ManyToOne(targetEntity="Compteurs", inversedBy="parametresMesure")
     * @ORM\JoinColumn(name="compteurs_id", referencedColumnName="id")
     */
    private $compteurs;

PointsComptage.php

class PointsComptage
{
    /**
     * @var \Doctrine\Common\Collections\Collection
     *
     * @ORM\OneToMany(targetEntity="Compteurs", mappedBy="pointsComptage")
     */
    private $compteurs;

如您所见,这些实体相互关联。

我创建了一个 table 来显示所有 PointsComptage 和我需要的数据到 table。 这是我的树枝视图中 table 的代码:

  <tbody>
    {% for currentPC in pointsComptage %}
      <tr>
        <td>{{ currentPC.ensembles}}</td>
        <td>{{ currentPC.nomPointComptage}}</td>
        <td>{{ currentPC.invariantPointComptage}}</td>
        <td>{{ currentPC.typesEnergie}}</td>
        <td>{{ currentPC.typesComptage}}</td>
        <td>{{ currentPC.consoProduction}}</td>
        <td>
          <a href="{{ path('detailsPointsComptage', {'id': currentPC.id }) }}"><button class="btn btn-info btn-xs">Détail</button></a>
          <a href="{{ path('modifierPointsComptage', {'id': currentPC.id }) }}"><button class="btn btn-warning btn-xs">Modifier</button></a>
        </td>
      </tr>
    {% endfor %}
  </tbody>

当然,目前一切正常。当我点击 details 按钮时,它会将我重定向到一个新页面,那里有另一个 table 显示我需要的所有数据 current点Comptage我选择之前(currentPC.id).

所以这是我显示详细信息页面的控制器方法:

public function detailsPointsComptageAction($id)
    {
      $em=$this->getDoctrine()->getManager();

      $detailPC = $this->getDoctrine()
                     ->getRepository('MySpaceMyBundle:PointsComptage')
                     ->findOneById($id);

      $compteur = $this->getDoctrine()
                     ->getRepository('MySpaceMyBundle:PointsComptage:Compteurs')
                     ->getCompteursAttributesByPC($id);


        return $this->render('MySpaceMyBundle:MyFolder:detailsPC.html.twig', array( 'detailsPC' => $detailPC, 'compteurs' => $compteur));
    }

简单说明一下:我恢复了我的currentPC的id 我点了显示他的详情页,在他的详情页我需要显示所有currentPC 关联的 compteurs 以及与这些 compteurs (ParametreMesure.php).

关联的所有其他属性

所以我在 CompteursRepository.php 中为 Compteurs 创建了一个 queryBuilder,我的 getCompteursAttributesByPC($id) method ($id 匹配 $id for PointsComptage.php).

这是用于以下目的的代码: CompteursRepository.php

public function getCompteursAttributesByPC($id)
  {
    $queryBuilder = $this->_em->createQueryBuilder();

    $queryBuilder
      ->select('pm', 'c')
      ->from('MySpaceMyBundle:PointsComptage', 'pc')
      ->from('MySpaceMyBundle:ParametresMesure', 'pm')
      ->leftJoin('MySpaceMyBundle:Compteurs', 'c', 'WITH', 'pm.compteurs = c.id')
      ->where('pc.id = c.pointsComptage ')
      ->andWhere('pc.id = :id')
      ->setParameter('id', $id);

      return $queryBuilder->getQuery()
                          ->getArrayResult();
  }

但是我的存储库方法有这个错误:

An exception occurred while executing 'SELECT c0_.id AS id_0, c0_.matricule_compteur AS matricule_compteur_1, c0_.mise_en_service_compteur AS mise_en_service_compteur_2, c0_.mise_hors_service_compteur AS mise_hors_service_compteur_3, p1_.id AS id_4, p1_.code_parametre AS code_parametre_5, p1_.nom_parametre AS nom_parametre_6 FROM points_comptage p2_ LEFT JOIN compteurs c0_ ON (p1_.compteurs_id = c0_.id), parametres_mesure p1_ WHERE p2_.id = c0_.pointscomptage_id AND p2_.id = ?' with params ["1"]:

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'p1_.compteurs_id' in 'on clause'

有人可以解释我如何恢复详细信息页面所需的所有数据并将它们显示在我的详细信息页面中吗?

我希望你能很好地理解我在这里试图做的事情: 一个 PointComptage -> 他的所有Compteurs -> Compteurs的所有ParametresMesure链接到PointComptage 我先选


更新-编辑

我按照@Jovan Perovic 的建议尝试使用此查询:

public function getCompteursAttributesByPC($id)
{
  $queryBuilder = $this->_em->createQueryBuilder();

  $queryBuilder
    ->select('pc')
    ->addSelect('pm')
    ->addSelect('c')
    ->from('MySpaceMyBundle:Compteurs', 'c')
    ->leftJoin('c.pointsComptage', 'pc')
    ->join('c.parametresMesure', 'pm')
    ->where('c.pointsComptage = :id')
    ->andWhere('c.id = pm.compteurs')
    ->setParameter('id', $id);

    return $queryBuilder->getQuery()
                        ->getScalarResult();
}

请注意,在我的 queryBuilder 中,我将 getArrayResult() 更改为 getScalarresult(),因为使用带有 getArrayResult 的 var 转储,我有这个:

array (size=2)
  0 => 
    array (size=6)
      'id' => int 5
      'matriculeCompteur' => string 'egfizegilf88' (length=12)
      'miseEnService' => 
        object(DateTime)[638]
          public 'date' => string '2012-05-15 00:00:00' (length=19)
          public 'timezone_type' => int 3
          public 'timezone' => string 'Europe/Paris' (length=12)
      'miseHorsService' => 
        object(DateTime)[684]
          public 'date' => string '2015-06-19 00:00:00' (length=19)
          public 'timezone_type' => int 3
          public 'timezone' => string 'Europe/Paris' (length=12)
      'pointsComptage' => 
        array (size=5)
          'id' => int 1
          'invariantPointComptage' => string 'invariant 1' (length=11)
          'nomPointComptage' => string 'test 1' (length=6)
          'codeDistribution' => string 'code test 1' (length=11)
          'localisationPointComptage' => string 'local test 1' (length=12)
      'parametresMesure' => 
        array (size=2)
          0 => 
            array (size=3)
              ...
          1 => 
            array (size=3)
              ...
  1 => 
    array (size=6)
      'id' => int 10
      'matriculeCompteur' => string 'ghhh666' (length=7)
      'miseEnService' => 
        object(DateTime)[642]
          public 'date' => string '2015-06-01 00:00:00' (length=19)
          public 'timezone_type' => int 3
          public 'timezone' => string 'Europe/Paris' (length=12)
      'miseHorsService' => 
        object(DateTime)[688]
          public 'date' => string '2015-06-19 00:00:00' (length=19)
          public 'timezone_type' => int 3
          public 'timezone' => string 'Europe/Paris' (length=12)
      'pointsComptage' => 
        array (size=5)
          'id' => int 1
          'invariantPointComptage' => string 'invariant 1' (length=11)
          'nomPointComptage' => string 'test 1' (length=6)
          'codeDistribution' => string 'code test 1' (length=11)
          'localisationPointComptage' => string 'local test 1' (length=12)
      'parametresMesure' => 
        array (size=1)
          0 => 
            array (size=3)
              ...

如您所见,ParametresMesure 没有结果。

并且使用 getScalarResult() 我有这个:

array (size=3)
  0 => 
    array (size=12)
      'c_id' => int 5
      'c_matriculeCompteur' => string 'egfizegilf88' (length=12)
      'c_miseEnService' => 
        object(DateTime)[638]
          public 'date' => string '2012-05-15 00:00:00' (length=19)
          public 'timezone_type' => int 3
          public 'timezone' => string 'Europe/Paris' (length=12)
      'c_miseHorsService' => 
        object(DateTime)[692]
          public 'date' => string '2015-06-19 00:00:00' (length=19)
          public 'timezone_type' => int 3
          public 'timezone' => string 'Europe/Paris' (length=12)
      'pc_id' => int 1
      'pc_invariantPointComptage' => string 'invariant 1' (length=11)
      'pc_nomPointComptage' => string 'test 1' (length=6)
      'pc_codeDistribution' => string 'code test 1' (length=11)
      'pc_localisationPointComptage' => string 'local test 1' (length=12)
      'pm_id' => int 1
      'pm_codeParametre' => string '658' (length=3)
      'pm_nomParametre' => string 'test 658' (length=8)
  1 => 
    array (size=12)
      'c_id' => int 5
      'c_matriculeCompteur' => string 'egfizegilf88' (length=12)
      'c_miseEnService' => 
        object(DateTime)[690]
          public 'date' => string '2012-05-15 00:00:00' (length=19)
          public 'timezone_type' => int 3
          public 'timezone' => string 'Europe/Paris' (length=12)
      'c_miseHorsService' => 
        object(DateTime)[684]
          public 'date' => string '2015-06-19 00:00:00' (length=19)
          public 'timezone_type' => int 3
          public 'timezone' => string 'Europe/Paris' (length=12)
      'pc_id' => int 1
      'pc_invariantPointComptage' => string 'invariant 1' (length=11)
      'pc_nomPointComptage' => string 'test 1' (length=6)
      'pc_codeDistribution' => string 'code test 1' (length=11)
      'pc_localisationPointComptage' => string 'local test 1' (length=12)
      'pm_id' => int 3
      'pm_codeParametre' => string 'gjgfjgfj489489' (length=14)
      'pm_nomParametre' => string 'hyhfhfhfhf' (length=10)
  2 => 
    array (size=12)
      'c_id' => int 10
      'c_matriculeCompteur' => string 'ghhh666' (length=7)
      'c_miseEnService' => 
        object(DateTime)[695]
          public 'date' => string '2015-06-01 00:00:00' (length=19)
          public 'timezone_type' => int 3
          public 'timezone' => string 'Europe/Paris' (length=12)
      'c_miseHorsService' => 
        object(DateTime)[642]
          public 'date' => string '2015-06-19 00:00:00' (length=19)
          public 'timezone_type' => int 3
          public 'timezone' => string 'Europe/Paris' (length=12)
      'pc_id' => int 1
      'pc_invariantPointComptage' => string 'invariant 1' (length=11)
      'pc_nomPointComptage' => string 'test 1' (length=6)
      'pc_codeDistribution' => string 'code test 1' (length=11)
      'pc_localisationPointComptage' => string 'local test 1' (length=12)
      'pm_id' => int 7
      'pm_codeParametre' => string 'ygyugyg' (length=7)
      'pm_nomParametre' => string 'bhkighfsighf' (length=12)

不同之处在于,使用 getScalarresult(),我的查询恢复链接到 Compteurs.phpParametresMesure.php 的数据,而使用 getArrayResult() 不是。

我的视图代码和我的控制器代码仍然相同,但我现在有这个错误:

Key "matriculeCompteur" for array with keys "c_id, c_matriculeCompteur, c_miseEnService, c_miseHorsService, pc_id, pc_invariantPointComptage, pc_nomPointComptage, pc_codeDistribution, pc_localisationPointComptage, pm_id, pm_codeParametre, pm_nomParametre" does not exist in MySpaceMyBundle:MyFolder:detailsPC.html.twig at line 41

第 41 行与此代码匹配:<td>{{ currentCompteur.matriculeCompteur}}</td>

如你所见,matriculeCompteur对应于我Compteurs.php实体中的$matriculeCompteur

这是我的代码,用于恢复与之前选择的 PointComptage 的 id 有关的所有链接到 compteurs 的数据,然后是所有链接到这些 Compteurs 的 ParametresMesure:

<tbody>
  {% for currentCompteur in compteurs %}
    <tr>
      <td>{{ currentCompteur.matriculeCompteur}}</td>
      <td>{{ currentCompteur.miseEnService|date("Y-m-d", "Europe/Paris")}}</td>
      <td>{{ currentCompteur.miseHorsService|date("Y-m-d", "Europe/Paris")}}</td>
      <td class="no-cell-padding">
        <table class="inner-table table stripe row-border order-column display table-bordered table-hover compact" cellspacing="0" width="100%">
            <tr>
              <td>code for parametresMesure</td>
              <td>code for parametresMesure</td>
              <td>code for parametresMesure</td>
              <td>code for parametresMesure</td>
            </tr>
        </table>
      </td>
    </tr>
  {% endfor %}
</tbody>

当您指定多个 FROM 时,后一个将覆盖前一个。

所以,而不是写:

$queryBuilder
      ->select('pm', 'c')
      ->from('MySpaceMyBundle:PointsComptage', 'pc')
      ->from('MySpaceMyBundle:ParametresMesure', 'pm')
      ->leftJoin('MySpaceMyBundle:Compteurs', 'c', 'WITH', 'pm.compteurs = c.id')
      ->where('pc.id = c.pointsComptage ')
      ->andWhere('pc.id = :id')
      ->setParameter('id', $id);

我相信你需要这样的东西:

$queryBuilder
      ->select('pc', 'c', 'pm')
      ->from('MySpaceMyBundle:PointsComptage', 'pc')
      ->join('pc.compteurs', 'c')
      ->leftJoin('c.parametresMesure', 'pm')
      ->where('pc.id = :id')
      ->setParameter('id', $id);

由于您没有从 PointsComptageParametresMesure 的直接 link,您首先需要加入 PointsComptageCompteurs,然后 CompteursParametresMesure.

请注意,我写了 ->join('pc.compteurs', 'c'),但根据您的逻辑,您可能想改用 leftJoin

这是您要实现的目标吗?

希望对您有所帮助。

我选择@Jovan Perovic 因为它让我找到了好的答案。这是我为查找结果而创建的 queryBuilder 的代码:

public function getCompteursAttributesByPC($id)
{
  $queryBuilder = $this->_em->createQueryBuilder();

  $queryBuilder
      ->select('c, pm, tu, tp')
      ->from('MySpaceMyBundle:Compteurs', 'c')
      ->leftJoin('c.pointsComptage', 'pc')
      ->leftJoin('c.parametresMesure', 'pm')
      ->leftJoin('pm.typesUnite', 'tu')
      ->leftJoin('pm.typesParametre', 'tp')
      ->where('c.pointsComptage = pc.id')
      ->andWhere('pm.compteurs = c.id')
      ->andWhere('pm.typesUnite = tu.id')
      ->andWhere('pm.typesParametre = tp.id')
      ->andWhere('identity(c.pointsComptage) = :id')
      ->add('orderBy', 'c.miseEnService', 'ASC')
      ->setParameter('id', $id);

      return $queryBuilder->getQuery()
                          ->getResult();
  }

在我的树枝视图中:

<tbody>
  {% for compteur in arrayCompteur %}
    <tr>
      <td>{{ compteur.matriculeCompteur}}</td>
      <td>{{ compteur.miseEnService|date("Y-m-d", "Europe/Paris")}}</td>
      <td>{{ compteur.miseHorsService|date("Y-m-d", "Europe/Paris")}}</td>
      <td>
        <table >
          <tr>
            <th>Code</th>
            <th>Nom</th>
            <th>Type</th>
            <th>Unité</th>
          </tr>
          {% for parametre in compteur.parametresMesure %}
            <tr>
              <td>
                {{ parametre.codeParametre}}
                {% if parametre.codeParametre is empty %}
                  <em>aucune informations</em>
                {% endif %}
              </td>
              <td>
                {{ parametre.nomParametre}}
                {% if parametre.nomParametre is empty %}
                  <em>aucune informations</em>
                {% endif %}
              </td>
              <td>
                {{ parametre.typesUnite}}
                {% if parametre.typesUnite is empty %}
                  <em>aucune informations</em>
                {% endif %}
              </td>
              <td>
                {{ parametre.typesParametre}}
                {% if parametre.typesParametre is empty %}
                  <em>aucune informations</em>
                {% endif %}
              </td>
            </tr>
          {% endfor %}
        </table>
      </td>
    </tr>
  {% endfor %}
</tbody>