Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #3913 (closed enhancement: fixed)

Opened 3 years ago

Last modified 3 years ago

[PATCH] eager loading with cascaded associations

Reported by: maiha Assigned to: David
Priority: normal Milestone:
Component: ActiveRecord Version: 1.0.0
Severity: normal Keywords: cascaded eager loading
Cc: charles.gerungan@gmail.com,maze@strahlungsfrei.de, technoweenie@gmail.com

Description

This patch removes limitation of depth for join levels. Now we can enjoy eager loadings without any limitations!!

# cascaded in two levels
>> Author.find(:all, :include=>{:posts=>:comments})
=> authors
     +- posts
          +- comments

# cascaded in two levels and normal association
>> Author.find(:all, :include=>[{:posts=>:comments}, :categorizations])
=> authors
     +- posts
          +- comments
     +- categorizations

# cascaded in two levels with two has_many associations
>> Author.find(:all, :include=>{:posts=>[:comments, :categorizations]})
=> authors
     +- posts
          +- comments
          +- categorizations

# cascaded in three levels
>> Company.find(:all, :include=>{:groups=>{:members=>{:favorites}}})
=> companies
     +- groups
          +- members
               +- favorites

Fortunately, a confliction for joining same tables was also resolved. So we can use eager loading on acts_as_tree.

>> TreeMixin.find(:all, :include=>"children")
=> mixins
     +- children

This means ticket #3836 is useless.

Best regards.

Attachments

cascaded_eager_loading.patch (24.8 kB) - added by maiha on 02/21/06 01:52:40.
cascaded_eager_2.3641.diff (27.1 kB) - added by rick on 02/25/06 05:28:45.

Change History

02/21/06 01:52:40 changed by maiha

  • attachment cascaded_eager_loading.patch added.

02/21/06 04:11:26 changed by david

Wow, this looks very promising. My cursory overview of the implementation hints that you've been able to make it cleaner AND more extendable.

02/21/06 20:02:26 changed by nzkoz

I've asked that this ticket get some serious testing before we apply it. It looks really nice but it's reasonably intrusive.

rails-core readers should be chiming in with their opinions.

02/21/06 21:34:42 changed by anonymous

  • cc set to charles.gerungan@gmail.com.

02/22/06 22:13:03 changed by anonymous

  • cc changed from charles.gerungan@gmail.com to charles.gerungan@gmail.com,maze@strahlungsfrei.de.

02/23/06 08:21:37 changed by procreate

Works for me.

02/25/06 04:17:46 changed by rick

AR error w/ sqlite:

  1) Error:
test_count_with_join(BasicsTest):
ActiveRecord::StatementInvalid: SQLite::Exceptions::SQLException: near "DISTINCT": syntax error: SELECT COUNT(DISTINCT p.id) FROM posts p, comments c WHERE p."type" = 'Post' AND p.id=c.post_id
    ./test/../lib/active_record/connection_adapters/abstract_adapter.rb:94:in `log'
    ./test/../lib/active_record/connection_adapters/sqlite_adapter.rb:137:in `execute'
    ./test/../lib/active_record/connection_adapters/sqlite_adapter.rb:157:in `select_all'
    ./test/../lib/active_record/connection_adapters/sqlite_adapter.rb:169:in `select_one'
    ./test/../lib/active_record/connection_adapters/abstract/database_statements.rb:16:in `select_value'
    ./test/../lib/active_record/base.rb:557:in `count_by_sql'
    ./test/base_test.rb:1077:in `test_count_with_join'

Other then that though, things look fine. I did notice you still can't eagerly load an association from the same table but different types.

FROM contents LEFT OUTER JOIN contents AS t1 ON t1.content_id = contents.id WHERE ( (contents."type" = 'Product' ) ) AND (contents."type" = 'Comment' )

It aliases the 2nd to t1, but AR doesn't know the alias at the time it adds the type query.

02/25/06 05:28:45 changed by rick

  • attachment cascaded_eager_2.3641.diff added.

02/25/06 05:32:44 changed by rick

  • cc changed from charles.gerungan@gmail.com,maze@strahlungsfrei.de to charles.gerungan@gmail.com,maze@strahlungsfrei.de, technoweenie@gmail.com.

I fixed the issue with the table aliases. The above example now resembles:

((contents."type" = 'Product')) AND (contents."type" = 'Comment' OR contents."type" IS NULL)

I added the IS NULL part so it would still show me all the products I want, even if no comments are available. This slightly skews two tests in the original eager associations for this very reason.

Anyways, I uploaded my revised patch.

02/25/06 05:33:36 changed by rick

Eh, I meant

((contents.type = 'Product')) AND (t1.type = 'Comment' OR t1.type IS NULL)

02/27/06 05:39:47 changed by anna@wota.jp

Thank you, Rick. I'll try your patch and fix the three problems that Jeremy pointed in rails-core ml.

03/04/06 23:40:00 changed by david

  • status changed from new to closed.
  • resolution set to fixed.

Applied in [3769].

03/05/06 14:56:36 changed by anonymous

awesome!