I’m building my own ORM that has three kinds of relations, but for the many-to-one relation I have a question.
Imagine that we have two tables, articles and categories. Each article can belong to a single category, therefore this relation is a many-to-one relation.
How relations work in use:
$category = $this->Model( 'Categories' )->get( array( 'pk' => 1 ) );
echo $category->title;
$article = $this->Model( 'Articles' )->get( array( 'pk' => 3 ) );
echo $article->category->title;
The example above loads and fills two model instances, one instance of a row from the categories table, one from the articles table.
The category node on $article contains an instance of a row from the categories table, the same one as $category. The first and second echo statements output the same data.
Now here’s where it gets tricky!
I’ve thought up the following: What if instance of a row from a table is cached the first time it’s initialized and stored in a ModelContainer static class, and each time a new row instance is requested it tests if that specific row has been cached and if it is, returns a reference to the instance in cache (when it’s not it will instantialize + cache the newly created instance)
If you don’t understand the above, let me put it simpler. Imagine there are 500 articles in your articles table, each belonging to the 12 categories in the categories table. If we use cached lazy initialization the way I described, there could only ever be 12 instances of rows from the categories table, the rest would be references. Let me illustrate it with code:
$article = $this->Model( 'Articles' )->get( array( 'pk' => 3 ) );
// At this point, the category instance gets instantialized and
// cached
echo $article->category->title;
$article2 = $this->Model( 'Articles' )->get( array( 'pk' => 4 ) );
// When the article belongs to the same category,
// this time we reference the already instantialized row
// of the same category
echo $article2->category->title;
The alternative to this is to use SQL JOIN statements to pre-load the many-to-one relation’s data into each row. The downside of doing that is that it loads the data even when you don’t need or use it, where with lazy initialization it does extra queries, but only when you ARE using it (have accessed the relation field’s property), and it’s limited to a specific amount (due to cached instances)
I need opinions on whether what I had in mind is a good way to do what I need it to do, or compelling arguments against it/for using JOIN statements instead.
Hope to get some thoughts on this!