渴望加载:正确的做事方式

时间:2012-03-10 00:46:35

标签: ruby-on-rails ruby database ruby-on-rails-3 eager-loading

我正在运行Ruby on Rails 3.1。我阅读了以下有关急切加载的文章和文档,我想找到一种正确的方法:

  1. Eager Loading Associations [官方文件]
  2. ActiveRecord::Associations::ClassMethods(参见“渴望加载协会”一节)[官方文件]
  3. Eager loading [博客文章]
  4. #2 说:

      

    请注意,使用 Post.includes([:author,:comments])等条件。其中(['comments.approved =?',true])。所有可能会产生意想不到的后果。< / p>

    #3 表示那些意想不到的后果是( note :示例非常相似所以我引用了博客文章的确切文字,但你必须保留注意解决方法,而不是具体实现):

      

    此查询,因为它将使用LEFT JOIN,也会丢弃所有帖子,而不会在其任何评论中添加带有“first”字样的评论。

    也就是说,如果存在非“关联”对象,则不会加载“主关联”对象。这是当我尝试通过在我的previous question中添加.where(:category_relationships => {:user_id => @current_user.id})之类的has_many来使用热切加载时所发生的情况,但我不希望这种情况发生。

    所以(失败主义者,因为我可能无法在{em>条件无法在@current_user.id语句中设置的情况下使用急切加载 - 请注意,在上面的代码中{{1是“动态设置”不同于提到的网站中的示例),我想知道是否存在pratiques /技术/策略以限制数据库查询,因为我有“N + 1问题”

    也许那些pratiques /技术/策略可以通过使用Ruby on Rails框架来实现...... #1 说:

      

    即使Active Record允许您指定热切的条件   加载关联就像连接一样,推荐的方法是使用   加入了。

    以正确的方式解决此问题的方法和方法是什么?


    也许解决方案是通过运行特定的和分离的数据库查询来检索和构建自己需要加载的内容,但问题是如何“传递”/“关联”/“插入”检索到的那些“将“对象”关联到“主关联”对象,以便可以使用“一种急切加载”方式?即,如何使用代码(请参阅mentioned question获取更多信息)以使用代码像@article.comments一样只获得我渴望加载的评论?在我的急切加载之后,是否可能 / 正确以制作类似@article.comments = my_eager_loaded_comments的内容,以便“传递”/“关联”/ “插入”对文章的评论?

2 个答案:

答案 0 :(得分:6)

  
    

在我急切加载之后,是否可以/正确地制作类似@ article.comments = my_eager_loaded_comments的内容以便“传递”/“关联”/“插入”评论到文章?

  

是的,有可能。我经常这样做。

请注意,我的解决方案仍会从数据库中检索所有关联的对象。如果条件是动态的,我认为没有任何解决方案可以只检索过滤的关联对象。我的解决方案侧重于过滤检索到的关联对象。

我假设要求get a list of articles和每篇文章eager load the comments of only one particular user

Article模型中:

def self.get_articles_with_comments_of_user( article_ids, user_id )
  articles = Article.where( id: article_ids ).includes( :comments )

  articles.each do |article|
    filtered_comments = article.comments.select { |comment| comment.user_id == user_id }
    article.association("comments").target = filtered_comments
  end

  articles
end

在上述方法返回的文章集合中,评论关联将只包含该特定用户的评论。

我希望这就是你所要求的。

答案 1 :(得分:2)

来自#2 ActiveRecord::Associations::ClassMethods来了:

  

如果您确实希望只加载一个关联的某些成员   通常更自然地包括具有条件的关联   在其上定义:

class Post < ActiveRecord::Base
  has_many :approved_comments,
    :class_name => 'Comment', 
    :conditions => ['approved = ?', true]
end

Post.includes(:approved_comments)
  

这会加载帖子并急切加载approved_comments关联,   其中仅包含已批准的评论。

如果我在上下文中正确理解了这一点,那么当您使用includes()将.where()应用于主查询时会出现歧义,并且AR会将整个查询的位置应用于限制您的主要结果的那些谓词。但是,如果您将谓词范围仅限于上述关联,则AR会理解并提供所有主要结果以及与其谓词条件匹配的相关对象。