2011-03-18 20 views
31

Cho phép nói rằng tôi có một bảng chứa thông tin về các lễ hội.
Mỗi lễ hội có ngày bắt đầu và ngày kết thúc.Làm cách nào để sử dụng một tiêu chí phức tạp bên trong kho lưu trữ của thực thể của học thuyết 2?

Tôi muốn chọn tất cả các lễ hội đang hoạt động (diễn ra) vào một ngày nhất định.
Có nghĩa là, tôi muốn chọn tất cả các lễ hội mà ngày bắt đầu của họ là trước hoặc vào một ngày cụ thể và ngày kết thúc của họ là sau hoặc vào cùng một ngày nhất định.

Vì vậy, tôi đã đi vào lớp kho lưu trữ của thực thể lễ hội, và tạo ra một phương pháp để làm điều đó.
Nhưng đối số tiêu chí "findBy" dự kiến ​​là một mảng, tất cả các ví dụ chỉ coi là tiêu chí đơn giản (ví dụ: "array ('name' => 'billy')" sẽ chọn tất cả các hàng có giá trị billy trong cột tên của họ), chỉ sử dụng toán tử so sánh.

Làm thế nào tôi có thể sử dụng các toán tử khác như

>, <, !=, IN, NOT IN, LIKE  

và vv?

Cảm ơn

+0

... Tôi cũng đồng ý về câu hỏi. Và lý tưởng, không có truy vấn thô, cũng như QueryBuilder .... nếu có thể. – renoirb

+0

bản sao có thể có của [Cách sử dụng phương thức findBy với tiêu chí so sánh] (http://stackoverflow.com/questions/14786937/how-to-use-a-findby-method-with-comparative-criteria) –

Trả lời

19

Bạn sẽ cần phải viết truy vấn của riêng mình (có thể sử dụng DQL) nếu bạn muốn điều gì đó cụ thể. Tôi tin rằng việc xây dựng trong "findBy" phương pháp được nhiều hơn cho chỉ grabbing đối tượng một cách nhanh chóng nếu bạn có ít tiêu chí cụ thể. Tôi không biết tên thực thể của bạn hoặc nơi chúng được lưu trữ. Có thể là một cái gì đó như thế này như là một chức năng trong Lễ hội Repository của bạn.

public function findActiveFestivals($start, $end) 
{ 
    $qb = $this->_em->createQueryBuilder(); 
    $qb->select('f') 
     ->from('Festival', 'f') 
     ->where('f.start >= :start') 
     ->andWhere('f.end <= :end') 
     ->setParameters(array('start' => $start, 'end' => $end)); 

    return $qb->getQuery()->getArrayResult(); 
} 
+3

Chỉ cần bạn biết - khi gọi $ this-> createQueryBuilder() từ bên trong lớp kho lưu trữ, bạn sẽ nhận được trình tạo truy vấn với bảng và bí danh đã được cấu hình – Doron

+4

đó không phải là câu trả lời thực cho câu hỏi được yêu cầu – David

+0

Nếu điều đó là không thể. Tôi cho rằng đó là câu trả lời đúng ... dựa vào thao tác QueryBuilder. – renoirb

8

thats không phải là câu trả lời cho câu hỏi Doron học thuyết có kho thực thể mà không làm cho chúng ta sử dụng truy vấn ở tất cả ...

$this->em->getRepository($this->entity)->findBy(array $criteria); 

nhưng những gì đã làm anh hỏi là làm thế nào để điều hành phức tạp trong mảng $ tiêu chí định dạng thông thường của mảng $criteriaarray('field'=> $value);

80

thuyết 2.3 bổ sung thêm một phương pháp matching() cho phép bạn sử dụng Criteria.

Ví dụ của Jeremy Hicks có thể được viết như thế này (lưu ý, điều này trả về một ArrayCollection thay vì một mảng).

public function findActiveFestivals($start, $end) 
{ 
    $expr = Criteria::expr(); 
    $criteria = Criteria::create(); 
    $criteria->where($expr->gte('start', $start)); 
    $criteria->andWhere($expr->lte('end', $end); 
    return $this->matching($criteria); 
} 

Cá nhân, tôi sẽ không sử dụng andWhere đây, và sử dụng nhiều hơn một vài dòng để cải thiện khả năng đọc, như thế này:

public function findActiveFestivals($start, $end) 
{ 
    $expr = Criteria::expr(); 
    $criteria = Criteria::create(); 
    $criteria->where(
     $expr->andX(
     $expr->gte('start', $start), 
     $expr->lte('end', $end) 
    ) 
    ); 
    return $this->matching($criteria); 
} 

Sử dụng một khoản IN là rất đơn giản.

public function findFestivalsByIds($ids) 
{ 
    $expr = Criteria::expr(); 
    $criteria = Criteria::create(); 
    $criteria->where($expr->in('id', $ids)); 
    return $this->matching($criteria); 
} 

Lớp Tiêu chuẩn là trong không-thực sự-ORM-hoặc-DBAL namespace Common thuyết, như ArrayCollection của họ (mà đã hỗ trợ tiêu dài hơn EntityRepository).

Ý nghĩa của nó là cách tách rời đối với mã không phải kho lưu trữ để tạo tiêu chí thứ hai. Vì vậy, nên sử dụng lớp này bên ngoài kho lưu trữ. QueryBuilder supports Criteria gần đây là tốt. Vì vậy, ngay cả khi xây dựng các truy vấn phức tạp hơn yêu cầu QueryBuilder, bạn có thể sử dụng Tiêu chí để cung cấp cho mã không phải là cơ sở dữ liệu linh hoạt trong những gì nó yêu cầu.

+0

Vì Doctrine 2.3 đây là câu trả lời đúng cho câu hỏi. Cảm ơn! – Wilt

+10

Trong doctrine/orm 2.5, EntityRepository :: matching sẽ trả về LazyCriteriaCollection để cho phép đếm mà không tìm nạp tất cả các hàng (https://github.com/doctrine/doctrine2/pull/882) –

+4

Ai đó có thể giải thích tại sao 'Criteria :: create() 'được sử dụng thay cho' tiêu chí mới() '? –

7

Tôi đã gặp phải vấn đề tương tự khi trở lại, nơi các kho lưu trữ Doctrine của tôi trở nên rất xấu do các truy vấn phức tạp. Tôi cũng phải chuyển đổi Yii ActiveRecord (với các đối tượng Criteria) thành Doctrine, và Doctrine không có các đối tượng Criteria vào lúc đó.

Tôi đã tìm thấy một blogpost by Benjamin Eberlei có giải pháp thú vị cho vấn đề này dựa trên specification pattern.

Nó cung cấp cho bạn khả năng trì hoãn thao tác của đối tượng Trình tạo truy vấn cho các lớp khác.

$spec = new AndX(
    new Equals('ended', 0), 
    new OrX(
     new LowerThan('endDate', new \DateTime()), 
     new AndX(
      new IsNull('endDate'), 
      new LowerThan('startDate', new \DateTime('-4weeks')) 
     ) 
    ) 
); 

return $this->em->getRepository('Advertisement')->match($spec)->execute() 

Bên cạnh đó bạn có thể soạn 2 hoặc nhiều lớp với nhau, mà tạo ra thoải mái khối xây dựng tái sử dụng:

public function myQuery(User $user) 
{ 
    $spec = new AndX(
     new ExpiredAds(), 
     new AdsByUser($user) 
    ); 

    return $this->em->getRepository('Advertisement')->match($spec)->execute(); 
} 

Trong trường hợp này ExpiredAds() và AdsByUser() chứa một cấu trúc giống như trong ví dụ mã đầu tiên .

Nếu bạn nghĩ rằng giải pháp mà sẽ làm việc cho bạn, hãy để tôi đề nghị hai thư viện mà bạn có thể cài đặt thông qua nhà soạn nhạc:

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