Keep loading some associations of one ORM object
I am creating a data model for a small application and would like to use an interesting loading in some methods - i.e. those where I know in advance that some associations will be used.
I read the Sequel :: Model :: Association manual for the method .eager
, but it confused me a little. A typical example would be:
Artist.eager( :albums => :tracks ).all
which loads all Artist objects with all their album fields preloaded and all tracks preloaded using only three queries. So far so good.
But I will say that I want to download one Artist by its master key and still have albums + tracks preloaded (still three requests, maybe much less than after associations for each album)? I don't see any example. A little experimenting gives me
Artist.eager( :albums => :tracks ).where( :id => id ).all.first
which at least works. I confirmed the impatience of loading by calling this, then disabling the db and showing that I can still access the associations.
However, I feel like I'm missing something. The construct that passes the primary key to the clause where
, gets the full set of data, and then asks for the first item, seems pretty awkward. I'm looking for something like this:
Artist.eager( :albums => :tracks )[ id ]
.., an easy way to declare that I want to load one object, and eagerly load some of its associations.
I found that I can create a custom association like this:
def eager_albums
albums_dataset.eager( :tracks ).all
end
but this is awkward to use because the code must request communication in a different way.
My question is, does my construct Artist.eager( :albums => :tracks ).where( :id => id ).all.first
do what I think it does in Sequel, and can I do better (simpler code)?
source to share
The call Artist.eager( :albums => :tracks ).where( :id => id ).all.first
selects all artists with id equal to "id" and then fetches the first artist from the results array (the call all
materializes the array). Typically this query will only return an array with one artist.
Only after you actually ask for a relationship artist.albums
or association outside of the album will additional requests be made.
You can just do Artist.eager( :albums => :tracks ).where( :id => id ).first
I am using a tactical loadable plugin for loading , so it doesn't need to be used at all as it detects when an association is used with a model instance that is part of a larger result set and automatically loads a loaded load of related models for the entire result set. Now your request becomes Artist[id]
orArtist[id].albums.all
Another handy plugin I use is proxy plugins so I don't have to deal with using association.some_array_method
vsassociation_dataset.some_ds_method
Finally, the dataset associations plugin allows you to describe a query starting from some model or model class and chaining through associations with the target model while allowing you to define constraints (or not) along the way.
For example, "find all tracks longer than 3 minutes on any album released in the last 2 weeks by UK-born artists":
Artist.where(country_of_birth: 'UK').albums.where{ release_date > Date.today - 14}.tracks.where{ duration > 3.minutes }.all
Hope this sheds some light.
source to share