Lazy Loading Behavior Question

Hello,

I have a question regarding the lazy loading AR approach.

I noticed that if I access a relation for the first time without defining any additional relation conditions etc during that access that the relation is saved in the model. This appears to prevent the AR model from performing the query again on subsequent accesses since the relation has already been loaded into the model’s memory.




//Example:

$myModel = User::model()->findByPk(1);	// executes query

$x = $myModel->myRelation;		// executes query

$y = $myModel->myRelation;		// does NOT execute query



This is the behavior I expected.

However, I noticed that if I access a relation for the first time where I DO specify additional relation conditions during that access, the relation is NOT saved in the model. This, of course, results in the AR model executing the query again on subsequent relation accesses.




//Example:

$myModel = User::model()->findByPk(1);					// executes query

$x = $myModel->myRelation(array('condition'=>'row_id='.$_GET['ID']));  	// executes query

$y = $myModel->myRelation;  						// executes query



I was expecting the second access of myRelation in the example above to return the results from the conditional relation access just before it without executing a query…

I ultimately need to pass a condition into my relation as shown in the second example because the condition is based on user input, and I want the retrieved relation set to be saved in the model so subsequent accesses of that relation do not result in repeating the query resulting in a decrease in efficiency.

The "work around" here appears to be that if I need to lazy load with a condition, I need to assign the retrieved lazy loaded relation models to the model relation like so:




$myModel->myRelation = $myModel->myRelation(array('condition'=>'row_id='.$_GET['ID'])); // executes query



Then on subsequent accesses of myRelation, the query will not be repeated since the model relation is already populated:




$y = $myModel->myRelation;	// does NOT execute query



This behavior seems odd to me. Is the intended behavior really that the relation should not be saved in the model if the relation is lazy loaded with additional conditions specified?

If so, is my “work around” the proper technique to accomplish my goal or did I miss something that isn’t as clumsy?

Thanks

hey why dont you do something like


$model = Model::model()->find(conditions id => 1, row_id => 2)


$relatedModel = $model->relatedModel // it only be performed when you access it

Hello,

row_id is an attribute of the relation model, not the parent model, so I don’t think I can do what you suggested…unless I missed something implied in your suggestion.

I also don’t want to eager load, essentially retrieving the relation by passing the row_id parameter in a ‘with’ clause because my application works like this:

I load the parent model for the user with a relation called company.

Then, based on the company the user works for, I lazy load one of three separate relations based on user input.

If you look at the detail of the relation query code ( I’m apparently too new to put in the link, but it’s line 242 of CActiveRecord.php ), you will see that it does not store the data in the relationship when you add filter criteria. When you add criteria to the relationship, it generates a "dynamic query" of sorts… in that you have not requested "myRelation", but a filtered version. Therefore, it does not save the results in "myRelation", because the results you retrieved are not an accurate representation of that relationship.

To avoid confusion down the road, my suggestion would be to store the results in a DIFFERENT property that better describes your filter, and then reference THAT property in later code. For example:




//Example:

$myModel = User::model()->findByPk(1);                                  // executes query

$myModel->mySelectedRelation = 

     $myModel->myRelation(array('condition'=>'row_id='.$_GET['ID']));   // executes query

$y = $myModel->myRelation;                                              // does NOT execute query