2012-04-16 23 views
7

Tôi đang sử dụng Symfony 2 với Doctrine và tôi có hai thực thể đã tham gia vào nhiều liên kết. Giả sử tôi có hai thực thể: Người dùng và Nhóm và các bảng có liên quan trên db là người dùng, nhóm và users_groups.DQL nhiều đến nhiều và đếm

Tôi muốn nhận được top 10 nhóm đông dân nhất trong DQL, nhưng tôi không biết cú pháp để thực hiện truy vấn trên bảng kết nối (users_groups). Tôi đã xem tài liệu hướng dẫn của Doctrine nhưng tôi không tìm thấy giải pháp, tôi đoán tôi vẫn còn rất nhiều điều để tìm hiểu về DQL.

Trong sql rõ ràng rằng sẽ là:

select distinct group_id, count(*) as cnt from users_groups group by group_id order by cnt desc limit 10 

bạn có thể vui lòng giúp tôi dịch này để DQL?

Cập nhật (lớp):

/** 
* Entity\E_User 
* 
* @ORM\Table(name="users") 
* @ORM\Entity 
*/ 
class E_User 
{ 
    /** 
    * @ORM\ManyToMany(targetEntity="E_Group", cascade={"persist"}) 
    * @ORM\JoinTable(name="users_groups", 
    *  joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id", onDelete="cascade")}, 
    *  inverseJoinColumns={@ORM\JoinColumn(name="group_id", referencedColumnName="id", onDelete="cascade")} 
    *) 
    */ 

    protected $groups; 

    /** 
    * @var integer $id 
    * 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

    /** 
    * @var string $name 
    * 
    * @ORM\Column(name="name", type="string", length=255) 
    */ 
    private $name; 

    /* ... other attributes & getters and setters ...*/ 
} 


/** 
* Entity\E_Group 
* 
* @ORM\Table(name="groups") 
* @ORM\Entity 
*/ 
class E_Group 
{ 
    /** 
    * @var integer $id 
    * 
    * @ORM\Column(name="id", type="integer") 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    private $id; 

    /** 
    * @var string $name 
    * 
    * @ORM\Column(name="text", type="string", length=255) 
    */ 
    private $name; 

    /* ... other attributes & getters and setters ...*/ 
} 

Trả lời

6

Nó không phải dễ dàng mà không nhìn thấy các lớp học thực tế, nhưng bằng cách đoán bạn có một mối quan hệ hai chiều nhiều-nhiều:

$dql = "SELECT g.id, count(u.id) as cnt FROM Entity\Group g " . 
    "JOIN g.users u GROUP BY g.id ORDER BY cnt DESC LIMIT 10;"; 
$query = $em->createQuery($dql); 
$popularGroups = $query->getArrayResult(); 

UPDATE:

Bạn không phải sử dụng mối quan hệ hai chiều, bạn có thể ery cách khác xung quanh:

$dql = "SELECT g.id, count(u.id) as cnt FROM Entity\User u " . 
    "JOIN u.groups g GROUP BY g.id ORDER BY cnt DESC LIMIT 10;"; 
+0

cảm ơn, sự cố là thực thể Nhóm không có liên kết được gọi là người dùng. Vì vậy, tôi nhận được ngoại lệ: [Semantical Error] dòng 0, col 72 gần 's GROUP BY g.id': Lỗi: Class Entity \ E_Group không có liên kết tên người dùng. Tôi đã cập nhật câu hỏi với các lớp thực tế. Tôi có nên thêm thuộc tính $ users vào thực thể E_Group để tạo mối quan hệ nhiều-nhiều-hai chiều không? –

+0

cảm ơn rất nhiều. Tôi đã kết thúc với một mối quan hệ hai chiều, anyway. Đó chỉ là một truy vấn giả để hiểu nó hoạt động như thế nào. cảm ơn lần nữa –

0

Đối với những người muốn xây dựng các truy vấn với học thuyết của QueryBuilder thay vì sử dụng DQL trực tiếp chăm giải pháp này.

Xin lưu ý rằng sự cố của tôi không phải là để có được nhóm người dùng hàng đầu, nhưng về mặt kỹ thuật vấn đề khá giống với tôi. Tôi làm việc với các bài đăng (như bài viết/bài đăng trên blog) và các thẻ được thêm vào bài đăng. Tôi cần xác định danh sách các bài đăng có liên quan (được xác định bằng cùng một thẻ). Danh sách đó phải được sắp xếp theo mức độ liên quan (các thẻ giống nhau mà một bài đăng khác có liên quan hơn).

Đây là phương pháp của lớp PostRepository tôi:

/** 
* Finds all related posts sorted by relavance 
* (from most important to least important) using 
* the tags of the given post entity. 
* 
* @param Post $post 
* 
* @return POST[] 
*/ 
public function findRelatedPosts(Post $post) { 
    // build query 
    $q = $this->createQueryBuilder('p') 
     ->addSelect('count(t.id) as relevance') 
     ->innerJoin('p.tags', 't') 
     ->where('t.id IN (:tags)') 
     ->setParameter('tags', $post->getTags()) 
     ->andWhere('p.id != :post') 
     ->setParameter('post', $post->getId()) 
     ->addGroupBy('p.id') 
     ->addOrderBy('relevance', 'DESC') 
     ->getQuery(); 

    // execute query and retrieve database result 
    $r = $q->execute(); 

    // result contains arrays, each array contains 
    // the actual post and the relevance value 
    // --> let's extract the post entities and 
    // forget about the relevance, because the 
    // posts are already sorted by relevance 
    $r = array_map(function ($entry) { 
     // first index is the post, second one 
     // is the relevance, just return the post 
     return reset($entry); 
    }, $r); 

    // array of posts 
    return $r; 
} 

Cảm ơn bạn @ Tom Imrei cho bạn giải pháp. Ngoài ra câu trả lời #26549597 rất hữu ích.

Các vấn đề liên quan