Doctrine 做了太多查询
Doctrine doing too much querys
我有多个实体,当我执行 findAll 时,一个实体上只有 1 个请求除外
/**
* @ORM\Entity(repositoryClass="App\Repository\PropertyRepository")
* @ORM\Table(name="property")
*/
class Property
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
* @Assert\Type("integer")
* @var int
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank
* @Assert\Choice({"Appartement", "Maison", "Garage", "Bureau", "Château", "Commerce"})
* @var string
*/
private $propertyCategory;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank
* @Assert\Type("string")
* @var string
*/
private $uniqueName;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank
* @Assert\Type("string")
* @var string
*/
private $address;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank
* @Assert\Type("string")
* @var string
*/
private $city;
/**
* @ORM\Column(type="integer")
* @Assert\NotBlank
* @Assert\Type("integer")
* @Assert\Length(min = 5, minMessage = "Ce champ doit contenir 5 chiffres")
* @Assert\Length(max = 5, maxMessage = "Ce champ doit contenir 5 chiffres")
* @var int
*/
private $zipCode;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank
* @Assert\Country
* @var string
*/
private $country;
/**
* @ORM\Column(type="integer")
* @Assert\NotBlank
* @Assert\Type("integer")
* @var string
*/
private $surfaceInSquareMeter;
/**
* @ORM\Column(type="integer")
* @Assert\NotBlank
* @Assert\Type("integer")
* @var int
*/
private $numberOfPiece;
/**
* @ORM\Column(type="text", nullable=true)
* @Assert\Type("string")
* @var string
*/
private $description;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank
* @Assert\Choice({"Meublé", "Non meublé"})
* @var string
*/
private $rentalCategory;
/**
* @ORM\Column(type="float")
* @Assert\NotBlank
* @Assert\Type("float")
* @var float
*/
private $rentExcludingCharges;
/**
* @ORM\Column(type="float")
* @Assert\NotBlank
* @Assert\Type("float")
* @var float
*/
private $charges;
/**
* @ORM\Column(type="float")
* @Assert\NotBlank
* @Assert\Type("float")
* @var float
*/
private $purchasePrice;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="properties")
* @JoinColumn(name="user_property_id", referencedColumnName="id", onDelete="CASCADE")
*/
private $userProperty;
/**
* @ORM\ManyToMany(targetEntity="App\Entity\Equipment", mappedBy="equipment")
*/
private $equipment;
/**
* @ORM\ManyToMany(targetEntity="App\Entity\Lessee", mappedBy="lessee")
*/
private $lessees;
/**
* @ORM\Column(type="string", length=255, nullable=true)
* @Assert\File(
* maxSize = "2000k",
* mimeTypes = {"application/pdf", "application/x-pdf"},
* mimeTypesMessage = "Choisisez un fichier PDF"
* )
*/
private $pdfFile;
我没有给你看 getter/setters 因为它超过 500 行但我生成了它们。
Doctrine 正在为每个 属性 执行 1 个查询。为了解决我的问题,我尝试这样做:
/**
* @param User $user
* @return array
*/
public function findPropertyByUser(User $user): array
{
$qb = $this->createQueryBuilder('p')
->andWhere('p.userProperty = :user')
->setParameter('user', $user)
->orderBy('p.id', 'ASC')
->getQuery();
return $qb->execute();
}
但它没有改变任何东西,我也尝试使用 findBy 但它没有改变任何东西。谁能告诉我我的问题出在哪里?
编辑:
根据评论,这可能是n+1的问题,
我尝试了不同的方法,但没有找到解决方案,这是我的实际方法:
/**
* @param User $user
* @return array
*/
public function findPropertyByUser(User $user): array
{
$qb = $this->createQueryBuilder('p')
->andWhere('p.userProperty = :user')
->setParameter('user', $user)
->orderBy('p.id', 'ASC')
->innerJoin('p.userProperty', 'u')
->addSelect('u')
->getQuery();
return $qb->execute();
}
终于 请求来自我的视图
{% if properties is defined %}
{% for property in properties %}
{% set emails = [property.userProperty.email] %}
{% for lessee in property.lessees.values %}
{% set emails = emails|merge([lessee.email]) %}
{% endfor %}
{% if app.user.email in emails %}
<tr>
<td>{{ property.propertyCategory }}</td>
<td>{{ property.uniqueName }}</td>
<td>{{ property.address }}</td>
<td>{{ property.city }}</td>
<td>{{ property.zipCode }}</td>
<td>{{ property.rentExcludingCharges }} €</td>
<td>{{ property.charges }} €</td>
<td>{{ property.purchasePrice }} €</td>
<td>
<a href="{{ path('property_show', {'id': property.id}) }}">Voir</a>
{% if is_granted('ROLE_USER') %}
<a href="{{ path('property_edit', {'id': property.id}) }}"><i class="fas fa-edit"></i> édition</a>
{% endif %}
</td>
</tr>
{% endif %}
{% endfor %}
{% else %}
<tr>
<td colspan="16">Vous n'avez pas enregistré de propriétés</td>
</tr>
{% endif %}
解决方案开始我少了一个要求:
/**
* @param User $user
* @return array
*/
public function findPropertyByUser(User $user): array
{
$qb = $this->createQueryBuilder('p')
->andWhere('p.userProperty = :user')
->setParameter('user', $user)
->orderBy('p.id', 'ASC')
->innerJoin('p.lessees', 'l')
->getQuery();
return $qb->execute();
}
您需要像这样的 leftJoin:
/**
* @param User $user
* @return array
*/
public function findPropertyByUser(User $user): array
{
$qb = $this->createQueryBuilder('p')
->leftJoin('p.lessees', 'l')
->andWhere('p.userProperty = :user OR l.email = :userEmail')
->setParameter('user', $user)
->setParameter('userEmail', $user->getEmail())
->orderBy('p.id', 'ASC')
->getQuery();
return $qb->execute();
}
并在视图中删除有关电子邮件的所有内容:
{% if properties is defined %}
{% for property in properties %}
<tr>
<td>{{ property.propertyCategory }}</td>
<td>{{ property.uniqueName }}</td>
<td>{{ property.address }}</td>
<td>{{ property.city }}</td>
<td>{{ property.zipCode }}</td>
<td>{{ property.rentExcludingCharges }} €</td>
<td>{{ property.charges }} €</td>
<td>{{ property.purchasePrice }} €</td>
<td>
<a href="{{ path('property_show', {'id': property.id}) }}">Voir</a>
{% if is_granted('ROLE_USER') %}
<a href="{{ path('property_edit', {'id': property.id}) }}"><i class="fas fa-edit"></i> édition</a>
{% endif %}
</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="16">Vous n'avez pas enregistré de propriétés</td>
</tr>
{% endif %}
我有多个实体,当我执行 findAll 时,一个实体上只有 1 个请求除外
/**
* @ORM\Entity(repositoryClass="App\Repository\PropertyRepository")
* @ORM\Table(name="property")
*/
class Property
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
* @Assert\Type("integer")
* @var int
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank
* @Assert\Choice({"Appartement", "Maison", "Garage", "Bureau", "Château", "Commerce"})
* @var string
*/
private $propertyCategory;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank
* @Assert\Type("string")
* @var string
*/
private $uniqueName;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank
* @Assert\Type("string")
* @var string
*/
private $address;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank
* @Assert\Type("string")
* @var string
*/
private $city;
/**
* @ORM\Column(type="integer")
* @Assert\NotBlank
* @Assert\Type("integer")
* @Assert\Length(min = 5, minMessage = "Ce champ doit contenir 5 chiffres")
* @Assert\Length(max = 5, maxMessage = "Ce champ doit contenir 5 chiffres")
* @var int
*/
private $zipCode;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank
* @Assert\Country
* @var string
*/
private $country;
/**
* @ORM\Column(type="integer")
* @Assert\NotBlank
* @Assert\Type("integer")
* @var string
*/
private $surfaceInSquareMeter;
/**
* @ORM\Column(type="integer")
* @Assert\NotBlank
* @Assert\Type("integer")
* @var int
*/
private $numberOfPiece;
/**
* @ORM\Column(type="text", nullable=true)
* @Assert\Type("string")
* @var string
*/
private $description;
/**
* @ORM\Column(type="string", length=255)
* @Assert\NotBlank
* @Assert\Choice({"Meublé", "Non meublé"})
* @var string
*/
private $rentalCategory;
/**
* @ORM\Column(type="float")
* @Assert\NotBlank
* @Assert\Type("float")
* @var float
*/
private $rentExcludingCharges;
/**
* @ORM\Column(type="float")
* @Assert\NotBlank
* @Assert\Type("float")
* @var float
*/
private $charges;
/**
* @ORM\Column(type="float")
* @Assert\NotBlank
* @Assert\Type("float")
* @var float
*/
private $purchasePrice;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="properties")
* @JoinColumn(name="user_property_id", referencedColumnName="id", onDelete="CASCADE")
*/
private $userProperty;
/**
* @ORM\ManyToMany(targetEntity="App\Entity\Equipment", mappedBy="equipment")
*/
private $equipment;
/**
* @ORM\ManyToMany(targetEntity="App\Entity\Lessee", mappedBy="lessee")
*/
private $lessees;
/**
* @ORM\Column(type="string", length=255, nullable=true)
* @Assert\File(
* maxSize = "2000k",
* mimeTypes = {"application/pdf", "application/x-pdf"},
* mimeTypesMessage = "Choisisez un fichier PDF"
* )
*/
private $pdfFile;
我没有给你看 getter/setters 因为它超过 500 行但我生成了它们。
Doctrine 正在为每个 属性 执行 1 个查询。为了解决我的问题,我尝试这样做:
/**
* @param User $user
* @return array
*/
public function findPropertyByUser(User $user): array
{
$qb = $this->createQueryBuilder('p')
->andWhere('p.userProperty = :user')
->setParameter('user', $user)
->orderBy('p.id', 'ASC')
->getQuery();
return $qb->execute();
}
但它没有改变任何东西,我也尝试使用 findBy 但它没有改变任何东西。谁能告诉我我的问题出在哪里?
编辑: 根据评论,这可能是n+1的问题,
我尝试了不同的方法,但没有找到解决方案,这是我的实际方法:
/**
* @param User $user
* @return array
*/
public function findPropertyByUser(User $user): array
{
$qb = $this->createQueryBuilder('p')
->andWhere('p.userProperty = :user')
->setParameter('user', $user)
->orderBy('p.id', 'ASC')
->innerJoin('p.userProperty', 'u')
->addSelect('u')
->getQuery();
return $qb->execute();
}
终于 请求来自我的视图
{% if properties is defined %}
{% for property in properties %}
{% set emails = [property.userProperty.email] %}
{% for lessee in property.lessees.values %}
{% set emails = emails|merge([lessee.email]) %}
{% endfor %}
{% if app.user.email in emails %}
<tr>
<td>{{ property.propertyCategory }}</td>
<td>{{ property.uniqueName }}</td>
<td>{{ property.address }}</td>
<td>{{ property.city }}</td>
<td>{{ property.zipCode }}</td>
<td>{{ property.rentExcludingCharges }} €</td>
<td>{{ property.charges }} €</td>
<td>{{ property.purchasePrice }} €</td>
<td>
<a href="{{ path('property_show', {'id': property.id}) }}">Voir</a>
{% if is_granted('ROLE_USER') %}
<a href="{{ path('property_edit', {'id': property.id}) }}"><i class="fas fa-edit"></i> édition</a>
{% endif %}
</td>
</tr>
{% endif %}
{% endfor %}
{% else %}
<tr>
<td colspan="16">Vous n'avez pas enregistré de propriétés</td>
</tr>
{% endif %}
解决方案开始我少了一个要求:
/**
* @param User $user
* @return array
*/
public function findPropertyByUser(User $user): array
{
$qb = $this->createQueryBuilder('p')
->andWhere('p.userProperty = :user')
->setParameter('user', $user)
->orderBy('p.id', 'ASC')
->innerJoin('p.lessees', 'l')
->getQuery();
return $qb->execute();
}
您需要像这样的 leftJoin:
/**
* @param User $user
* @return array
*/
public function findPropertyByUser(User $user): array
{
$qb = $this->createQueryBuilder('p')
->leftJoin('p.lessees', 'l')
->andWhere('p.userProperty = :user OR l.email = :userEmail')
->setParameter('user', $user)
->setParameter('userEmail', $user->getEmail())
->orderBy('p.id', 'ASC')
->getQuery();
return $qb->execute();
}
并在视图中删除有关电子邮件的所有内容:
{% if properties is defined %}
{% for property in properties %}
<tr>
<td>{{ property.propertyCategory }}</td>
<td>{{ property.uniqueName }}</td>
<td>{{ property.address }}</td>
<td>{{ property.city }}</td>
<td>{{ property.zipCode }}</td>
<td>{{ property.rentExcludingCharges }} €</td>
<td>{{ property.charges }} €</td>
<td>{{ property.purchasePrice }} €</td>
<td>
<a href="{{ path('property_show', {'id': property.id}) }}">Voir</a>
{% if is_granted('ROLE_USER') %}
<a href="{{ path('property_edit', {'id': property.id}) }}"><i class="fas fa-edit"></i> édition</a>
{% endif %}
</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="16">Vous n'avez pas enregistré de propriétés</td>
</tr>
{% endif %}