2013-04-27 59 views
0

已更新在底部:原则查询生成器连接添加表两次

我想要做什么应该是两个表之间的简单连接。我使用Symfony2(2.2)构建了一个简单的乐队网站,其中有一个Gig桌子和一个Venue桌子。这是我第一次使用Symfony2和教义,所以我可能完全走错了方向。我用DataFixtures创建并填充了表,并验证了ID关系是正确的。我得到的问题是生成的DQL查询具有在FROM部分中引用两次的Gig表,并且这导致我找回相同记录的多个实例,而不是我期望的x个记录数。我不知道我在做什么错,因为这会发生。另外,这样做可能更简单,但我正在探索我的所有选项,因为我在构建网站的过程中自学Symfony2。

Gig表包含一个指向Venue表的venue_id,该表在Gig实体中定义为ManyToOne关系(如下所示)。使用教条查找所有的一切似乎都正常工作正常填充Gig实体中的Venue类。我正在尝试创建一些最新Gig的平面视图,以便在头版上显示,所以我想我会尝试使用Join并仅包含我需要的字段。

这里是库查询:

public function getGigsWithLimit($maxGigs) 
{ 
    $qb = $this->createQueryBuilder('b') 
     ->select(' 
      g.gigDate, 
      g.startTime, 
      g.endTime, 
      g.message1 as gig_message1, 
      g.message2 as gig_message2, 
      g.url, 
      v.name, 
      v.address1, 
      v.address2, 
      v.city, 
      v.state, 
      v.zip, 
      v.phone, 
      v.url as venue_url, 
      v.message1 as venue_message1, 
      v.message2 as venue_message2, 
      v.message3 as venue_message3' 
     ) 
     ->from('WieldingBassBundle:Gig', 'g') 
     ->leftJoin('g.venue', 'v') 
     ->orderBy('g.gigDate', 'DESC') 
     ->setMaxResults($maxGigs); 

    return $qb->getQuery()->getResult(); 

} 

下面是它创建DQL:

SELECT 
    g0_.id AS id0, 
    g0_.gig_date AS gig_date1, 
    g0_.start_time AS start_time2, 
    g0_.end_time AS end_time3, 
    g0_.message1 AS message14, 
    g0_.message2 AS message25, 
    g0_.url AS url6, 
    v1_.name AS name7, 
    v1_.address1 AS address18, 
    v1_.address2 AS address29, 
    v1_.city AS city10, 
    v1_.state AS state11, 
    v1_.zip AS zip12, 
    v1_.phone AS phone13, 
    v1_.url AS url14, 
    v1_.message1 AS message115, 
    v1_.message2 AS message216, 
    v1_.message3 AS message317 
FROM 
    Gig g2_, 
    Gig g0_ 
LEFT JOIN 
    Venue v1_ ON g0_.venue_id = v1_.id 
LIMIT 
    6 

千兆g2_是我的问题。如果我删除它并执行查询,一切都如预期。我不知道是什么造成的。

第一台演出实体看起来是这样的(我离开了getter和setter):

/** 
* Gig 
* 
* @ORM\Table() 
* @ORM\Entity(repositoryClass="Wielding\BassBundle\Entity\GigRepository") 
* @ORM\HasLifecycleCallbacks 
*/ 
class Gig 
{ 
/** 
* @var integer 
* 
* @ORM\Column(name="id", type="integer") 
* @ORM\Id 
* @ORM\GeneratedValue(strategy="AUTO") 
*/ 
private $id; 

/** 
* @var \DateTime 
* 
* @ORM\Column(name="gig_date", type="date") 
*/ 
private $gigDate; 

/** 
* @var \DateTime 
* 
* @ORM\Column(name="start_time", type="datetime") 
*/ 
private $startTime; 

/** 
* @var \DateTime 
* 
* @ORM\Column(name="end_time", type="datetime") 
*/ 
private $endTime; 

/** 
* @var string 
* 
* @ORM\Column(name="message1", type="string", length=50, nullable=true) 
*/ 
private $message1; 

/** 
* @var string 
* 
* @ORM\Column(name="message2", type="string", length=50, nullable=true) 
*/ 
private $message2; 

/** 
* @var string 
* 
* @ORM\Column(name="url", type="string", length=128, nullable=true) 
*/ 
private $url; 

/** 
* @var integer 
* 
* @ORM\Column(name="venue_id", type="integer") 
*/ 
private $venueId; 

/** 
* @ORM\Column(type="datetime") 
*/ 
protected $created; 

/** 
* @ORM\Column(type="datetime") 
*/ 
protected $updated; 


/** 
* @ORM\ManyToOne(targetEntity="Venue", cascade="persist") 
* @ORM\JoinColumn(name="venue_id", referencedColumnName="id") 
*/ 
protected $venue; 

的地点表很简单,没有定义,因此任何关系,我会离开它,除非它被要求。

任何想法?谢谢你的帮助。

安德鲁

我删除了除你会重现问题,这里的一切是什么我留下了:

我简化了存储库的方法:

public function getGigsWithLimit2($maxGigs) 
{ 
    $qb = $this->createQueryBuilder('a') 
     ->select('g.id') 
     ->from('WieldingBassBundle:Gig', 'g') 
     ->setMaxResults($maxGigs); 

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

现在,这产生:

SELECT 
    g0_.id AS id0 
FROM 
    Gig g1_, 
    Gig g0_ 
LIMIT 
    6 

还有那个问题g1 g1_问题。我从Symfony的探查的“解释查询”,它表明:

id select_type table type possible_keys key key_len ref rows  Extra 
1 SIMPLE g1_ index  IDX_ED7D664240A73EBA 4  9  Using index 
1 SIMPLE g0_ index  IDX_ED7D664240A73EBA 4  9 Using index; Using join buffer 

我不假装知道是什么意思,但它显示了它是如何使用不同的信息都表项。

回答

0

我发现了这个问题。我不习惯教义,并且在不需要它的存储库中使用 - >,因为实体通过注释自动关联。我以前的查询工作是在控制器中,而不是一个存储库,所以 - > from是必要的。

0

如果您已经拥有包含外键的“场地”,那么“venueId”的用法是什么?

+0

我对此很好奇。它似乎工作正常,但我没有意识到外键是自动创建的。我将尝试删除它。谢谢。 – akwebb1 2013-04-28 12:01:19

0

您正在尝试执行SQL。学说是不同的。您的查询提取每个字段。学说更喜欢获取实体。我想你也许想要这个:

public function getGigsWithLimit($maxGigs) 
{ 
    $qb = $this->createQueryBuilder('g') 
     ->leftJoin('g.venue', 'v') 
     ->orderBy('g.gigDate', 'DESC') 
     ->setMaxResults($maxGigs); 

    return $qb->getQuery()->getResult(); 

} 

返回结果是实体的名单,你可以直接调用所有的具体方法。如果您想要部分对象,仍然欢迎您指定带有教义的字段,但我发现提取整个实体的常规方法可以满足我的大多数需求。

这是一个与SQL根本不同的范例,需要一些习惯。