使用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是电影的集合,其成员通过连接对象FilmCollectionFilm表示。 FilmCollectionFilm有一个位置列,因此集合的给定成员可以重新排序(像电影队列一样),因此我们需要连接对象而不是has_and_belongs_to_many。
当我尝试一次性加载多个集合的电影时,我的问题就出现了。
调用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
根据连接对象中的位置正确对影片进行排序。
但是调用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)
收集正确的电影,但忽略查询第二部分的顺序。如果在使用.includes()
进行加载加载但仍然没有n + 1查询时,如何保留各个连接对象的排序?
答案 0 :(得分:2)
事实证明,你可以通过明确地包括连接对象以及通过它的关联来解决这个问题。下面的行将正确选择所有内容,并保留连接对象上存在的任何条件/顺序。
FilmCollection.includes(film_collection_films: :film)
如果只做FilmCollection.includes(:films)
,那么无论如何它都会选择FilmCollectionFilms然后只是扔掉它们。因此,上面的代码将完成相同数量的工作,但正确构建查询。