Lazy vs Eager Loading Help

Hello, I’m hoping someone can help me understand what’s going on with a particular query. I have two classes that relate to each other:

models/App.php




class App extends CActiveRecord {

  public function relations () {

    return array(

      "questions" => array(self::HAS_MANY, "Question", "question"),

    );

  }


  public function __construct () {

    foreach ($this->questions as $question) {

      // Do something...

    }

  }

}



models/Question.php




class Question extends CActiveRecord {

  public function relations () {

    return array(

      "app" => array(self::BELONGS_TO, "App", "app"),

    );

  }

}



controllers/AppController.php




public class AppController extends CController {

  public function actionIndex () {

    // Try #1

    $apps = App::model()->findAll();


    // Try #2

    //$apps = App::model()->with("questions")->findAll();

  }

}



I have logging/profiling turned on and when my controller executes actionIndex (with “Try #1”), it’s prints out that Yii is “lazy loading App.questions”.

When my controller executes actionIndex (with “Try #2”), it STILL prints out “lazy loading App.questions” but I also ONLY get Application objects that have questions (i.e. I’m not getting Application objects that have no questions). To further illustrate that point, let’s say I have 10 applications, 7 of which have questions associated with them. “Try #1” returns 10 objects, “Try #2” returns only 7.

So my question, what am I doing wrong here? Why can’t I get eager loading to work properly? And why am I only getting 7 results back using “with” when I expected to get 10? Thanks for any and all help as this has been driving me crazy!

Ok, so I figured out one issue… I keep getting the “lazy loading” message because I’m accessing the relationship in a constructor. If I get rid of the constructor and move the code into it’s own function, it looks like eager loading works properly.

However, my other question still stands - how can I truly get all “App” objects even if they don’t have any questions associated with them?

And in typical fashion…I have answered my final question after toiling with this for hours prior to posting. What I failed to mention in my original post was I had a “condition” set in the App’s “questions” relation. That is what was filtering out the Apps without any questions.

I believe I am set now. I apologize for wasting forum space…

Hi

You can avoid not selection apps without questions by using a left outer join rather than a left inner join.

Further you may be interested in reading http://www.yiiframework.com/wiki/527/relational-query-lazy-loading-and-eager-loading-with-and-together/ .

Finally, I advise you to lok at my extension for relations http://www.yiiframework.com/extension/relatedsearchbehavior/ . If you look at the queries generated in the demo, you can see that they are minimum. It is not 100% eager loading, but it uses the ‘keen loading’ behavior which loads selected related fields after selecting the records first;