2012-01-12 31 views
16

Giả sử tôi có hai thực thể trong dự án Symfony2 của tôi: CategoryArticle (một danh mục có nhiều bài viết).Doctrine2 (Doctrine 2.1) mong muốn tải trong Symfony2

Trong CategoryRepository tôi, tôi có phương pháp này:

findAllDummy(){ 
    return $this->createQueryBuilder('c') 
       ->leftJoin('c.Articles a') 
       ->getQuery()->getResult(); 
} 

Nếu tôi nhớ tốt, trong Symfony1.4 (và các phiên bản tương ứng của Học thuyết), các đối tượng trở sẽ có thuộc tính 'bài' của họ lấp đầy bởi các đối tượng Article tương ứng. Bây giờ, trong Symfony2, các đối tượng Proxy được trả về.

Vì vậy, nếu tôi lặp qua các bài viết của một danh mục cụ thể, Vì nhiều truy vấn dưới dạng lặp lại sẽ được thực hiện.

foreach($category->getArticles() as $article){ 
    echo $article->getDoctrine() 
       ->getRepository('')getTitle(); 
} 

Tôi hiểu đây là hành vi tải chậm mặc định của Doctrine2.1.

Câu hỏi 1: giải pháp này tốt hơn như thế nào? N truy vấn thay vì 1.

tôi đã cố gắng để buộc tải háo hức bằng cách làm như sau:

findAllDummy(){ 
    return $this->createQueryBuilder('c') 
       ->leftJoin('c.articles a') 
       ->getQuery() 
       ->setFetchMode('Category', 'articles', 'EAGER') 
       ->getResult(); 
} 

Nhưng kết quả vẫn giữ nguyên.

Câu hỏi 2: cách bắt buộc tải dữ liệu trong Doctrine2?

Trả lời

18

Bạn đang tham gia một bảng nhưng bạn không chọn bất kỳ thứ gì từ bảng đó. Thêm ->addSelect('a') vào trình tạo truy vấn của bạn. Hãy xem xét hai truy vấn SQL sau đây để hiểu sự khác biệt:

SELECT a.id, a.title 
FROM article a 
JOIN category c ON a.category_id = c.id 
WHERE a.id = 123; 

SELECT a.id, a.title, c.id, c.name 
FROM article a 
JOIN category c ON a.category_id = c.id 
WHERE a.id = 123; 

Háo hức/lười biếng tham gia không có gì để làm với các truy vấn DQL. Nó xác định những gì cần được nạp khi bạn sử dụng $articleRepository->find(123).

+0

@Crozin Tôi vẫn còn hơi bối rối ... khi bạn nói "nó định nghĩa những gì cần được tải", bạn có đề cập đến những gì được ngậm nước không? –

+1

@SamSelikoff Vâng, nếu bạn định nghĩa 'fetch = EAGER' trên quan hệ của bài viết, tất cả các bài báo sẽ được nạp (và ngậm nước) khi bạn gọi' categoryRepository-> findOne (321) ' – Crozin

+0

Sự khác nhau giữa tải và dưỡng ẩm là gì? –

-2

Đó là giải pháp tốt hơn vì các phép nối là một quá trình đắt hơn nhiều so với truy vấn đơn giản. Trong khi nó có vẻ không hiệu quả, nó không phải là một sự lãng phí, và nhanh chóng trở nên hiệu quả hơn khi bạn không tải từng bit của mọi đối tượng liên quan.

1

Trong phần nơi bạn cố gắng "buộc tải háo hức" vấn đề có thể là bạn nên sử dụng phương pháp fetchMode với kiểu biến cho sai đối số $fetchMode. Bạn vượt qua một chuỗi 'EAGER' nhưng phương pháp không mong đợi một chuỗi nhưng một số nguyên.

Phương pháp này hy vọng hằng từ lớp ClassMetadata:

/** 
* Specifies that an association is to be fetched when it is first accessed. 
*/ 
const FETCH_LAZY = 2; 

/** 
* Specifies that an association is to be fetched when the owner of the 
* association is fetched. 
*/ 
const FETCH_EAGER = 3; 

Trong tài liệu hướng dẫn chương thuyết 14.7.6.6. Tạm thời thay đổi lấy chế độ trong DQL bạn có thể thấy một ví dụ về cách sử dụng này:

$query->setFetchMode("MyProject\User", "address", \Doctrine\ORM\Mapping\ClassMetadata::FETCH_EAGER); 

Vì vậy, vượt qua hoặc là một tham chiếu đến hằng số hay một số nguyên tương ứng với chế độ mà bạn muốn sử dụng.

0

Như đã nói trong số doctrine docs, tải háo hức trong trường hợp này sẽ không tạo ra bất kỳ sự khác biệt nào vì bạn có mối quan hệ một-nhiều giữa Danh mục và Bài viết.

Đối với quan hệ một-nhiều, thay đổi chế độ tìm nạp thành mong muốn sẽ thực hiện một truy vấn cho mỗi thực thể gốc được tải. Điều này không có cải thiện so với chế độ tìm nạp lười và cũng sẽ khởi tạo các liên kết trên cơ sở từng người một khi chúng được truy cập.

Vì vậy, trái với những gì @Crozin đã nói, bạn vẫn có thể tải dữ liệu lên DQL. Nếu bạn có mối quan hệ một-một hoặc nhiều-một, việc tải mong muốn sẽ giải quyết được vấn đề tạo thêm các truy vấn. Tuy nhiên để giải quyết vấn đề của bạn trong trường hợp này, bạn nên sử dụng ->addSelect('a') như @Crozin đã đề cập.

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