Query Builder SingleValuedAssociationField expected #5825

Open
opened 2026-01-22 15:18:58 +01:00 by admin · 6 comments
Owner

Originally created by @shubaivan on GitHub (Dec 28, 2017).

I have native sql query with left join when have on with or condition, how to represent it in query builder ?

 $query = "  SELECT  te.id
            FROM    task_executions AS te
            INNER JOIN tasks AS t ON t.id = te.task_id
            LEFT JOIN cost_objects AS co ON co.id = t.cost_object_id
            LEFT JOIN cost_object_managers AS com ON com.cost_object_id = co.id OR com.cost_object_id = co.parent_id

and I need represent it in query builder but in User entity I have ManyToMany relation, without separate table and when I try left join with condition I have error SingleValuedAssociationField expected.

User entity

class User
{
...
/**
 * @ORM\ManyToMany(targetEntity="CostObject", mappedBy="users")
 */
private $costObjects;
}

CostObject entity

class CostObject
{
    /**
 * @var CostObject
 *
 * @ORM\ManyToOne(targetEntity="CostObject", inversedBy="children")
 * @ORM\JoinColumns({
 *   @ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="CASCADE")
 * })
 */
private $parent;

    /**
 * @var ArrayCollection
 *
 * @ORM\ManyToMany(targetEntity="User", inversedBy="costObjects")
 * @ORM\JoinTable(name="cost_object_managers",
 *      joinColumns={@ORM\JoinColumn(name="cost_object_id", referencedColumnName="id", onDelete="CASCADE")},
 *      inverseJoinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id", onDelete="CASCADE")}
 * )
 */
private $users;

and my query builder without condition

        $qb->select('te')
        ->from('AppBundle:TaskExecution', 'te')
        ->innerJoin('te.task', 't')

        ->leftJoin('t.costObject', 'co')
        ->leftJoin('co.users', 'com')

this is $query->getSQL()

SELECT some_name FROM task_executions t0_ INNER JOIN tasks t1_ ON t0_.task_id = t1_.id LEFT JOIN cost_objects c2_ ON t1_.cost_object_id = c2_.id LEFT JOIN cost_object_managers c4_ ON c2_.id = c4_.cost_object_id LEFT JOIN users u3_ ON u3_.id = c4_.user_id ORDER BY t0_.execution_start DESC

and I need change it like in nativbe query but when I add condition to left join I get error

query with condition

        $qb->select('te')
        ->from('AppBundle:TaskExecution', 'te')
        ->innerJoin('te.task', 't')

        ->leftJoin('t.costObject', 'co')
        ->leftJoin(
            'co.users',
            'com',
            Join::WITH,
            $qb->expr()->orX
                (
                    'com.costObjects = co.id',
                    'com.costObjects = co.parent'
                )
            )

and error

[Semantical Error] line 0, col 121 near 'costObjects =': Error: Invalid PathExpression. StateFieldPathExpression or SingleValuedAssociationField expected.

I try add IDENTITY like reсomended me in answer

        ->leftJoin('t.costObject', 'co')
        ->leftJoin(
            'co.users',
            'com',
            Join::WITH,
            $qb->expr()->orX
                (
                    'IDENTITY(com.costObjects) = co.id',
                    'IDENTITY(com.costObjects) = co.parent'
                )
            )

but still have error

[Semantical Error] line 0, col 130 near 'costObjects)': Error: Invalid PathExpression. Must be a SingleValuedAssociationField.
Originally created by @shubaivan on GitHub (Dec 28, 2017). I have native sql query with left join when have on with or condition, how to represent it in query builder ? $query = " SELECT te.id FROM task_executions AS te INNER JOIN tasks AS t ON t.id = te.task_id LEFT JOIN cost_objects AS co ON co.id = t.cost_object_id LEFT JOIN cost_object_managers AS com ON com.cost_object_id = co.id OR com.cost_object_id = co.parent_id and I need represent it in query builder but in `User` entity I have ManyToMany relation, without separate table and when I try left join with condition I have error `SingleValuedAssociationField expected.` User entity class User { ... /** * @ORM\ManyToMany(targetEntity="CostObject", mappedBy="users") */ private $costObjects; } CostObject entity class CostObject { /** * @var CostObject * * @ORM\ManyToOne(targetEntity="CostObject", inversedBy="children") * @ORM\JoinColumns({ * @ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="CASCADE") * }) */ private $parent; /** * @var ArrayCollection * * @ORM\ManyToMany(targetEntity="User", inversedBy="costObjects") * @ORM\JoinTable(name="cost_object_managers", * joinColumns={@ORM\JoinColumn(name="cost_object_id", referencedColumnName="id", onDelete="CASCADE")}, * inverseJoinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id", onDelete="CASCADE")} * ) */ private $users; and my query builder without condition $qb->select('te') ->from('AppBundle:TaskExecution', 'te') ->innerJoin('te.task', 't') ->leftJoin('t.costObject', 'co') ->leftJoin('co.users', 'com') this is `$query->getSQL()` SELECT some_name FROM task_executions t0_ INNER JOIN tasks t1_ ON t0_.task_id = t1_.id LEFT JOIN cost_objects c2_ ON t1_.cost_object_id = c2_.id LEFT JOIN cost_object_managers c4_ ON c2_.id = c4_.cost_object_id LEFT JOIN users u3_ ON u3_.id = c4_.user_id ORDER BY t0_.execution_start DESC and I need change it like in nativbe query but when I add condition to left join I get error query with condition $qb->select('te') ->from('AppBundle:TaskExecution', 'te') ->innerJoin('te.task', 't') ->leftJoin('t.costObject', 'co') ->leftJoin( 'co.users', 'com', Join::WITH, $qb->expr()->orX ( 'com.costObjects = co.id', 'com.costObjects = co.parent' ) ) and error [Semantical Error] line 0, col 121 near 'costObjects =': Error: Invalid PathExpression. StateFieldPathExpression or SingleValuedAssociationField expected. I try add `IDENTITY` like reсomended me in answer ->leftJoin('t.costObject', 'co') ->leftJoin( 'co.users', 'com', Join::WITH, $qb->expr()->orX ( 'IDENTITY(com.costObjects) = co.id', 'IDENTITY(com.costObjects) = co.parent' ) ) but still have error [Semantical Error] line 0, col 130 near 'costObjects)': Error: Invalid PathExpression. Must be a SingleValuedAssociationField.
Author
Owner

@Majkl578 commented on GitHub (Dec 28, 2017):

Since com.costObjects seems to be to-many collection, you should use MEMBER OF. This should work:

co MEMBER OF com.costObjects OR co.parent MEMBER OF com.costObjects
@Majkl578 commented on GitHub (Dec 28, 2017): Since `com.costObjects` seems to be to-many collection, you should use `MEMBER OF`. This should work: ``` co MEMBER OF com.costObjects OR co.parent MEMBER OF com.costObjects ```
Author
Owner

@shubaivan commented on GitHub (Dec 28, 2017):

@Majkl578 how should I apply this approach to my query ? How should look orX in my leftJoin ?

@shubaivan commented on GitHub (Dec 28, 2017): @Majkl578 how should I apply this approach to my query ? How should look `orX` in my `leftJoin` ?
Author
Owner

@Majkl578 commented on GitHub (Dec 28, 2017):

It's orX(), so:

$qb->expr()->orX(
    'co MEMBER OF com.costObjects',
    'co.parent MEMBER OF com.costObjects'
)
@Majkl578 commented on GitHub (Dec 28, 2017): It's orX(), so: ``` $qb->expr()->orX( 'co MEMBER OF com.costObjects', 'co.parent MEMBER OF com.costObjects' ) ```
Author
Owner

@shubaivan commented on GitHub (Dec 28, 2017):

@Majkl578
I debuged it and got sql, this looks

SELECT name FROM task_executions t0_ INNER JOIN tasks t1_ ON t0_.task_id = t1_.id LEFT JOIN cost_objects c2_ ON t1_.cost_object_id = c2_.id LEFT JOIN cost_object_managers c4_ ON c2_.id = c4_.cost_object_id 

exactly:

LEFT JOIN users u3_ ON u3_.id = c4_.user_id AND (EXISTS (SELECT 1 FROM cost_object_managers c5_ INNER JOIN cost_objects c6_ ON c5_.cost_object_id = c6_.id WHERE c5_.user_id = u3_.id AND c6_.id IN (c2_.id)) OR EXISTS (SELECT 1 FROM cost_object_managers c5_ INNER JOIN cost_objects c6_ ON c5_.cost_object_id = c6_.id WHERE c5_.user_id = u3_.id AND c6_.id IN (c2_.parent_id)))

do you yhink this is equals to ?

LEFT JOIN cost_object_managers AS com ON com.cost_object_id = co.id OR com.cost_object_id = co.parent_id
@shubaivan commented on GitHub (Dec 28, 2017): @Majkl578 I debuged it and got sql, this looks SELECT name FROM task_executions t0_ INNER JOIN tasks t1_ ON t0_.task_id = t1_.id LEFT JOIN cost_objects c2_ ON t1_.cost_object_id = c2_.id LEFT JOIN cost_object_managers c4_ ON c2_.id = c4_.cost_object_id exactly: LEFT JOIN users u3_ ON u3_.id = c4_.user_id AND (EXISTS (SELECT 1 FROM cost_object_managers c5_ INNER JOIN cost_objects c6_ ON c5_.cost_object_id = c6_.id WHERE c5_.user_id = u3_.id AND c6_.id IN (c2_.id)) OR EXISTS (SELECT 1 FROM cost_object_managers c5_ INNER JOIN cost_objects c6_ ON c5_.cost_object_id = c6_.id WHERE c5_.user_id = u3_.id AND c6_.id IN (c2_.parent_id))) do you yhink this is equals to ? LEFT JOIN cost_object_managers AS com ON com.cost_object_id = co.id OR com.cost_object_id = co.parent_id
Author
Owner

@shubaivan commented on GitHub (Dec 29, 2017):

@Majkl578
Because WITH this is additional condition. I said about change ON condition for leftJoin this is different case
Now sql look like

LEFT JOIN users u3_ ON u3_.id = c4_.user_id AND (EXISTS (SELECT 1 FROM cost_object_managers c5_ INNER JOIN cost_objects c6_ ON c5_.cost_object_id = c6_.id WHERE c5_.user_id = u3_.id AND c6_.id IN (c2_.id)) OR EXISTS (SELECT 1 FROM cost_object_managers c5_ INNER JOIN cost_objects c6_ ON c5_.cost_object_id = c6_.id WHERE c5_.user_id = u3_.id AND c6_.id IN (c2_.parent_id)))

I want change this relation users u3_ ON u3_.id = c4_.user_id

by

LEFT JOIN cost_object_managers AS com ON com.cost_object_id = co.id OR com.cost_object_id = co.parent_id

@shubaivan commented on GitHub (Dec 29, 2017): @Majkl578 Because `WITH` this is additional condition. I said about change `ON` condition for `leftJoin` this is different case Now sql look like ``` LEFT JOIN users u3_ ON u3_.id = c4_.user_id AND (EXISTS (SELECT 1 FROM cost_object_managers c5_ INNER JOIN cost_objects c6_ ON c5_.cost_object_id = c6_.id WHERE c5_.user_id = u3_.id AND c6_.id IN (c2_.id)) OR EXISTS (SELECT 1 FROM cost_object_managers c5_ INNER JOIN cost_objects c6_ ON c5_.cost_object_id = c6_.id WHERE c5_.user_id = u3_.id AND c6_.id IN (c2_.parent_id))) ``` I want change this relation `users u3_ ON u3_.id = c4_.user_id` by ``` LEFT JOIN cost_object_managers AS com ON com.cost_object_id = co.id OR com.cost_object_id = co.parent_id ```
Author
Owner

@shubaivan commented on GitHub (Dec 29, 2017):

@Majkl578
But when I changed WITH to ON

            ->leftJoin(
                'co.users',
                'com',
                Join::ON,
                $qb->expr()->orX(
                    'co MEMBER OF com.costObjects',
                    'co.parent MEMBER OF com.costObjects'
                )
            )

I have error

[Syntax Error] line 0, col 112: Error: Expected end of string, got 'ON'

@shubaivan commented on GitHub (Dec 29, 2017): @Majkl578 But when I changed `WITH` to `ON` ``` ->leftJoin( 'co.users', 'com', Join::ON, $qb->expr()->orX( 'co MEMBER OF com.costObjects', 'co.parent MEMBER OF com.costObjects' ) ) ``` I have error `[Syntax Error] line 0, col 112: Error: Expected end of string, got 'ON'`
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#5825