如何从Doctrine仓库获取鉴别器类型?单表继承场景查询问题
I’ve run into this exact issue with Doctrine’s single table inheritance (STI) before. The problem arises because Doctrine manages the discriminator field internally by default—it’s not mapped as a regular property on your entity, so trying to select it directly in DQL throws an error. Here are the most reliable ways to solve this:
1. Map the Discriminator as a Read-Only Property
The cleanest approach is to explicitly map the discriminator field to a read-only property on your base Flux entity. This lets you safely select it in queries or access it via a getter method.
Update your base Flux entity like this:
<?php namespace App\Entity; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity(repositoryClass="App\Repository\FluxRepository") * @ORM\InheritanceType("SINGLE_TABLE") * @ORM\DiscriminatorColumn(name="type", type="string") * @ORM\DiscriminatorMap({ * "flux_type_a" = FluxTypeA::class, * "flux_type_b" = FluxTypeB::class * }) */ abstract class Flux { // ... your existing entity properties and methods /** * @ORM\Column(name="type", type="string", readOnly=true) * Note: The name must match the @DiscriminatorColumn name exactly */ private string $type; public function getType(): string { return $this->type; } }
Key notes here:
- The
@Columnname must match thenamevalue in@DiscriminatorColumn(in your case, "type"). - Setting
readOnly=trueis critical—it tells Doctrine not to attempt to update this field, since it’s strictly managed by the STI mapping.
Once you’ve added this, you can include f.type in your repository queries without issues:
// In FluxRepository public function getAllFluxWithType(): array { return $this->createQueryBuilder('f') ->select('f', 'f.type') ->getQuery() ->getResult(); }
2. Use INSTANCE OF for Type Checks (If Filtering is Your Goal)
If you don’t need to select the type string but just want to filter or check the object’s concrete type, use Doctrine’s INSTANCE OF operator in DQL, or PHP’s native instanceof after fetching entities.
Example DQL Filter:
SELECT f FROM App\Entity\Flux f WHERE f INSTANCE OF App\Entity\FluxTypeA
Example PHP Type Check:
$allFlux = $this->getDoctrine()->getRepository(Flux::class)->findAll(); foreach ($allFlux as $flux) { if ($flux instanceof FluxTypeA) { // Handle type A logic } elseif ($flux instanceof FluxTypeB) { // Handle type B logic } }
3. Native SQL Query (If You Can’t Modify the Entity)
If modifying the entity isn’t an option, you can use a native SQL query to fetch the discriminator field along with your entity data. Here’s a quick example:
// In FluxRepository public function getAllFluxWithTypeNative(): array { $conn = $this->getEntityManager()->getConnection(); $sql = 'SELECT * FROM flux'; // Replace with your actual table name $resultSet = $conn->executeQuery($sql); return $resultSet->fetchAllAssociative(); }
Keep in mind this returns raw arrays instead of Doctrine entities, so use this only as a last resort.
Common Pitfalls to Avoid
- Mismatched Column Names: Ensure the
namein@Columnmatches exactly what’s in@DiscriminatorColumn—case sensitivity matters depending on your database. - Forgetting
readOnly=true: Without this, Doctrine will try to persist changes to the discriminator field, leading to errors since it’s managed by STI. - Overusing Native Queries: Mapping the read-only property is almost always better than falling back to native SQL, as it keeps your code consistent with Doctrine’s entity management.
内容的提问来源于stack exchange,提问作者Liora Haydont

