Symfony2:Left Join 产生错误的查询
Symfony2: Left Join producing wrong query
我正在尝试使用这样的原则查询生成器来构建查询:
$q = $this
->createQueryBuilder('u')
->select('u, r')
->leftJoin('u.roles', 'r')
->where('u.username = :username OR u.email = :email')
->setParameter('username', $username)
->setParameter('email', $username)
->getQuery();`
此代码产生 2 个查询:
查询 1 正确
SELECT t0.user_id AS user_id1, t0.username AS username2, t0.salt AS salt3, t0.password AS password4, t0.email AS email5, t0.is_active AS is_active6, t0.created AS created7, t0.updated AS updated8, t0.last_login AS last_login9
FROM users t0
WHERE t0.username = ?
LIMIT 1
查询 2 不正确:
SELECT t0.role_id AS role_id1, t0.role AS role2
FROM roles t0
INNER JOIN user_role ON t0.id = user_role.role_id
WHERE user_role.user_fk = ?
查询 2 应该是:
SELECT t0.role_id AS role_id1, t0.role AS role2
FROM roles t0
INNER JOIN user_role ON t0.role_id = user_role.role_fk
WHERE user_role.user_fk = ?
Entity\Role 看起来像这样:
/**
* @ORM\Table(name="roles")
* @ORM\Entity(repositoryClass="XXX\XXXBundle\Entity\Repository\RoleRepository")
*/
class Role implements RoleInterface
{
/**
* @ORM\Id
* @ORM\Column(name="role_id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $_roleId;
/**
* @ORM\Column(name="role", type="string", length=20, unique=true)
*/
protected $_role;
/**
* @ORM\ManyToMany(targetEntity="User", mappedBy="roles")
* @ORM\JoinTable(name="user_role",
* joinColumns={@ORM\JoinColumn(name="role_fk", referencedColumnName="role_id")})
*/
private $_users;
...
Entity\User 看起来像这样:
class User implements UserInterface, \Serializable
{
/**
* @ORM\Column(name="user_id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $_userId;
...
/**
* @ORM\ManyToMany(targetEntity="Role", inversedBy="users")
* @ORM\JoinTable(name="user_role",
* joinColumns={@ORM\JoinColumn(name="user_fk", referencedColumnName="user_id")})
*/
protected $_roles;
...
Entity\Role 代码中的注释说明了要使用的列名称,语句的 SELECT 部分使用了正确的名称。语句的 WHERE 部分使用了正确的列 user_role.user_fk,这是在 Entity\User 代码中定义的。
如何停止 doctrine 使用不存在的列名并为语句的 INNER JOIN 部分使用定义的列名?
我找到了一个有效的解决方案。
Entity\User 需要更改以在注释中包含 inverseJoinColumns,如下所示:
/**
* @ORM\ManyToMany(targetEntity="Role", inversedBy="_users")
* @ORM\JoinTable(name="user_role",
* joinColumns={@ORM\JoinColumn(name="user_fk", referencedColumnName="user_id")},
* inverseJoinColumns={@ORM\JoinColumn(name="role_fk", referencedColumnName="role_id")})
*/
protected $_roles;
Entity\Role 需要更改以包括这样的 inverseJoinColumns:
/**
* @ORM\ManyToMany(targetEntity="User", mappedBy="_roles")
* @ORM\JoinTable(name="user_role",
* joinColumns={@ORM\JoinColumn(name="role_fk", referencedColumnName="role_id")},
* inverseJoinColumns={@ORM\JoinColumn(name="user_fk", referencedColumnName="user_id")})
*/
private $_users;
createQueryBuilder 代码需要如下所示:
$q = $this
->createQueryBuilder('u')
->select('u, r')
->from('XXXXXXBundle:User', 'u')
->leftJoin('u.roles', 'r', \Doctrine\ORM\Query\Expr\Join::ON, 'user_role.role_kf = r.role_id')
->where('u.username = :username OR u.email = :email')
->setParameter('username', $username)
->setParameter('email', $username)
->getQuery();
我正在尝试使用这样的原则查询生成器来构建查询:
$q = $this
->createQueryBuilder('u')
->select('u, r')
->leftJoin('u.roles', 'r')
->where('u.username = :username OR u.email = :email')
->setParameter('username', $username)
->setParameter('email', $username)
->getQuery();`
此代码产生 2 个查询:
查询 1 正确
SELECT t0.user_id AS user_id1, t0.username AS username2, t0.salt AS salt3, t0.password AS password4, t0.email AS email5, t0.is_active AS is_active6, t0.created AS created7, t0.updated AS updated8, t0.last_login AS last_login9
FROM users t0
WHERE t0.username = ?
LIMIT 1
查询 2 不正确:
SELECT t0.role_id AS role_id1, t0.role AS role2
FROM roles t0
INNER JOIN user_role ON t0.id = user_role.role_id
WHERE user_role.user_fk = ?
查询 2 应该是:
SELECT t0.role_id AS role_id1, t0.role AS role2
FROM roles t0
INNER JOIN user_role ON t0.role_id = user_role.role_fk
WHERE user_role.user_fk = ?
Entity\Role 看起来像这样:
/**
* @ORM\Table(name="roles")
* @ORM\Entity(repositoryClass="XXX\XXXBundle\Entity\Repository\RoleRepository")
*/
class Role implements RoleInterface
{
/**
* @ORM\Id
* @ORM\Column(name="role_id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $_roleId;
/**
* @ORM\Column(name="role", type="string", length=20, unique=true)
*/
protected $_role;
/**
* @ORM\ManyToMany(targetEntity="User", mappedBy="roles")
* @ORM\JoinTable(name="user_role",
* joinColumns={@ORM\JoinColumn(name="role_fk", referencedColumnName="role_id")})
*/
private $_users;
...
Entity\User 看起来像这样:
class User implements UserInterface, \Serializable
{
/**
* @ORM\Column(name="user_id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $_userId;
...
/**
* @ORM\ManyToMany(targetEntity="Role", inversedBy="users")
* @ORM\JoinTable(name="user_role",
* joinColumns={@ORM\JoinColumn(name="user_fk", referencedColumnName="user_id")})
*/
protected $_roles;
...
Entity\Role 代码中的注释说明了要使用的列名称,语句的 SELECT 部分使用了正确的名称。语句的 WHERE 部分使用了正确的列 user_role.user_fk,这是在 Entity\User 代码中定义的。
如何停止 doctrine 使用不存在的列名并为语句的 INNER JOIN 部分使用定义的列名?
我找到了一个有效的解决方案。
Entity\User 需要更改以在注释中包含 inverseJoinColumns,如下所示:
/**
* @ORM\ManyToMany(targetEntity="Role", inversedBy="_users")
* @ORM\JoinTable(name="user_role",
* joinColumns={@ORM\JoinColumn(name="user_fk", referencedColumnName="user_id")},
* inverseJoinColumns={@ORM\JoinColumn(name="role_fk", referencedColumnName="role_id")})
*/
protected $_roles;
Entity\Role 需要更改以包括这样的 inverseJoinColumns:
/**
* @ORM\ManyToMany(targetEntity="User", mappedBy="_roles")
* @ORM\JoinTable(name="user_role",
* joinColumns={@ORM\JoinColumn(name="role_fk", referencedColumnName="role_id")},
* inverseJoinColumns={@ORM\JoinColumn(name="user_fk", referencedColumnName="user_id")})
*/
private $_users;
createQueryBuilder 代码需要如下所示:
$q = $this
->createQueryBuilder('u')
->select('u, r')
->from('XXXXXXBundle:User', 'u')
->leftJoin('u.roles', 'r', \Doctrine\ORM\Query\Expr\Join::ON, 'user_role.role_kf = r.role_id')
->where('u.username = :username OR u.email = :email')
->setParameter('username', $username)
->setParameter('email', $username)
->getQuery();