简体   繁体   English

rails 4通过关联在has_many上使用includes时保留连接对象顺序

[英]rails 4 preserve join object order when using includes on a has_many through association

Using Rails 4.1.6 and Ruby 2.1.2 and given the following three objects: 使用Rails 4.1.6和Ruby 2.1.2并给出以下三个对象:

class FilmCollection
  has_many :film_collection_films, -> { order(:position) }
  has_many :films, through: :film_collection_films
end

class FilmCollectionFilm
  belongs_to :film_collection_film
  belongs_to :film
end

class Film
  has_many :film_collection_films
end

FilmCollections are collections of films, and its members are represented via the join object FilmCollectionFilm. FilmCollections是电影的集合,其成员通过连接对象FilmCollectionFilm表示。 FilmCollectionFilm has a column for position, so that a given member of a collection can be re-ordered (think like a film queue) and thus why we need the join object and not a has_and_belongs_to_many. FilmCollectionFilm有一个位置列,因此集合的给定成员可以重新排序(像电影队列一样),因此我们需要连接对象而不是has_and_belongs_to_many。

My problem occurs when I try to eager load the films of multiple collections at once. 当我试图一次性加载多个集合的电影时,我的问题就出现了。

Calling FilmCollection.first.films will get me a query that looks like: 调用FilmCollection.first.films会给我一个看起来像这样的查询:

SELECT `film_collections`.* FROM `film_collections`
  ORDER BY `film_collections`.`id` ASC LIMIT 1
SELECT `films`.* FROM `films`
  INNER JOIN `film_collection_films` ON `films`.`id` = `film_collection_films`.`film_id`
  WHERE `film_collection_films`.`extensional_film_collection_id` = 1
  ORDER BY `film_collection_films`.`position` ASC

Which orders the films correctly based on the position in the join object. 根据连接对象中的位置正确对电影进行排序。

But instead calling FilmCollection.includes(:films).first.films will get me the following query: 但是相反,调用FilmCollection.includes(:films).first.films会得到以下查询:

SELECT `film_collections`.* FROM `film_collections`
  ORDER BY `film_collections`.`id` ASC LIMIT 1
SELECT `film_collection_films`.* FROM `film_collection_films`
  WHERE `film_collection_films`.`film_collection_id` IN (1)
  ORDER BY `film_collection_films`.`position` ASC
SELECT `films`.* FROM `films`  WHERE `films`.`id` IN (1, 16, 53, 185)

Which gathers the correct films but disregards the order in the second part of the query. 哪个收集正确的电影但忽略了查询第二部分的顺序。 How can I preserve ordering respective of the join object when eager loading with .includes() but still not have an n+1 query? 当急切加载.includes()但仍然没有n + 1查询时,如何保留连接对象的相应顺序?

It turns out that you can solve this by explicitly including the join object as well as the association that is through it. 事实证明,您可以通过显式包含连接对象以及通过它的关联来解决此问题。 The line below will select everything correctly, and preserve any conditionals/ordering present on the join object as well. 下面的行将正确选择所有内容,并保留连接对象上存在的任何条件/顺序。

FilmCollection.includes(film_collection_films: :film)

If you do just FilmCollection.includes(:films) then it will select the FilmCollectionFilms anyway and then just toss them. 如果你只做FilmCollection.includes(:films)那么无论如何它都会选择FilmCollectionFilms然后只是扔掉它们。 So, the above code will do about the same amount of work but build the query correctly. 因此,上面的代码将完成相同数量的工作,但正确构建查询。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM