2010-10-26 29 views
5

Tôi có câu hỏi như thế này:Làm cách nào để tạo tiêu chí với truy vấn phức tạp trong khung công tác Yii?

SELECT * FROM activity 
WHERE (((userId = 1 OR userId IN(SELECT userId FROM follower WHERE followerId = 1)) 
AND activityType IN(1, 2, 3)) 
OR (targetId = 24 AND aType IN(1, 2, 3, 4, 5))) 
ORDER BY id DESC; 

Tôi đã cố gắng sử dụng model()->findAllBySql($sql) và nó hoạt động. Nhưng tôi muốn sử dụng nó bằng cách sử dụng CDbCriteria, nếu bạn có giải pháp khác cho tôi biết: D

+1

Một câu hỏi cũ nhưng tôi cần phải bình luận. Khi xử lý các truy vấn phức tạp ** KHÔNG ** sử dụng bất kỳ ORM nào. Bạn phải đối phó với SQL thuần túy (AR cung cấp phương thức 'findAllBySql()'). –

+0

@Andrzej Ośmiałowski bạn có thể cho chúng tôi lý do tại sao chúng ta nên sử dụng findAllBySql thay vì sử dụng ORM (Tiêu chí). – aslingga

Trả lời

7

Bạn vẫn có thể xây dựng tuyên bố điều này với một CDbCriteria Tôi nghĩ rằng ... một cái gì đó như:

$criteria=new CDbCriteria; 
$criteria->condition = ' 
    (
    (
     userId = 1 OR 
     userId IN (SELECT userId FROM follower WHERE followerId = 1) 
    ) 
    AND activityType IN(1, 2, 3) 
) 
    OR (
    targetId = 24 
    AND aType IN(1, 2, 3, 4, 5) 
) 
'; 
$criteria->order = 'id DESC'; 
$results=Activity::model()->findAll($criteria); 

Như thời điểm này bạn cũng có thể chỉ cần viết một câu lệnh SQL thông thường, nhưng có thể có một số lợi ích cho làm nó theo cách này: ràng buộc params, sáp nhập các tiêu chí, tiêu chí bổ sung thêm vv

6

Miễn là SQL đơn giản của bạn hoạt động, bạn an toàn. Có rất nhiều lần tôi phải ném Active Record đi và chỉ hoàn thành công việc theo cách của người chơi.

Tôi đã cố gắng chuyển truy vấn này thành cấu trúc CDbCriteria có thể đọc được. Ý tưởng tồi. Yii hút khi nói đến truy vấn dữ liệu phức tạp.

+0

Cảm ơn bạn @pestaa, tôi hy vọng Yii sẽ đưa ra một giải pháp cho truy vấn phức tạp: D – aslingga

+1

@aslingga Về cơ bản là "thiết kế sai". Tôi không nói rằng tôi có thể làm tốt hơn, mặc dù. – pestaa

+0

một chút sau, nhưng 5 năm sau, bạn sẽ giới thiệu khung làm việc nào? – Tebe

1

Câu trả lời có thể được tìm thấy ở đây: http://www.yiiframework.com/doc/guide/1.1/en/database.dao#executing-sql-statements

Trong trường hợp của bạn:

$sql = 'SELECT * FROM activity'; 
$sql .= 'WHERE (((userId = 1 OR userId IN(SELECT userId FROM follower WHERE followerId = 1))'; 
$sql .= 'AND activityType IN(1, 2, 3))'; 
$sql .= 'OR (targetId = 24 AND aType IN(1, 2, 3, 4, 5)))'; 
$sql .= 'ORDER BY id DESC'; 

$connection = Yii::app()->db; 
$command = $connection->createCommand($sql); 
$results = $command->queryAll(); 

@pestaa là đúng mà đôi khi bạn phải ném kỷ lục hoạt động ra ngoài cửa sổ. Điều này đặc biệt đúng nếu bạn đang thực hiện cập nhật hàng loạt trong đó lặp qua nhiều mô hình là không hiệu quả khủng khiếp.

+0

Cảm ơn bạn @philip cho giải pháp của bạn nhưng bây giờ tôi muốn sử dụng CDbCriteria trong Active Record của tôi. Tôi đã cố gắng sử dụng sql và thực hiện bằng cách sử dụng Activity :: model() -> findAllBySql ($ sql) và tôi nghĩ rằng nó sẽ cho kết quả tương tự như bằng cách sử dụng SQL Comamnd. : D – aslingga

+0

@aslingga, là câu hỏi của bạn về việc sử dụng CDbCriteria và cách tạo một tuyên bố như vậy? Nếu có, hãy cho tôi biết và có thể tôi có thể giúp. Một trong những ưu điểm của CDbCriteria là nó kết hợp các tham số ràng buộc, đó là điều cần thiết trong việc ngăn chặn SQL injection nếu bạn đang truy vấn với đầu vào của người dùng. Tôi đã không cố gắng tuyên bố của bạn ở trên, nhưng tôi thấy không có lý do tại sao nó sẽ không hoạt động. –

+0

Tôi muốn kết hợp nó với CPanigation trong Yii, có cách nào để làm cho nó có thể? – aslingga

0

Chỉ cần sử dụng CSqlDataProvider http://www.yiiframework.com/doc/api/1.1/CSqlDataProvider

Disclaimer: tôi biết nó không phải là câu trả lời chính xác để q particural này uestion nhưng nó có thể giúp làm việc xung quanh vấn đề đã được đưa ra. Tôi nghi ngờ mục đích chính của câu hỏi này là nhận được cách để sử dụng CGridView, CListView vv với SQL tùy ý.

0

Tôi sử dụng CDbCriteria cho các truy vấn phức tạp mà tôi sử dụng tính năng with.

Bạn có thể xây dựng các tiêu chí phức tạp như thế này:

$dbCriteria->with=array(
    '<relation1>'=>array('condition'=>'<condition for given relation>', 
     'with'=>array('<relation2:relation of relation1>' 
      =>array(<conditions for relation2>) 
     ) 
     'scopes'=><scopes for relation1> 
    ) 
); 

tôi đã không kiểm tra như thế nào OR có thể nhận được vào chơi ở đây.

Bằng cách sử dụng phạm vi, bạn cũng có thể chèn một số tiêu chí phức tạp hơn và vẫn giữ điều kiện tìm kiếm của bạn có thể đọc được.

Điều này khá mạnh mẽ. Tôi chưa thấy 'hướng dẫn' hoàn chỉnh về điều này; Tôi đã kết luận điều này từ mã nguồn.

+0

bạn có thể thêm một ví dụ không? tôi không thể hiểu được cách sao chép điều này trong cuộc sống thực – realtebo

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