包括,连接和选择轨道4

时间:2015-11-18 22:08:14

标签: mysql ruby-on-rails ruby activerecord

我尝试使用rails 4进行非常简单的查询,但我遇到了意外问题......

我有一个带有翻译表的Country模型(通过globalize gem)。我想获取当前区域设置中的每个国家/地区名称,国家/地区ID以及short_code我存储在Country模型中的countries = Country.select('countries.id, countries.short_code, country_translations.name').joins(:translations)

我的第一个方法是这句话:

SELECT countries.id, countries.short_code, country_translations.name 
    FROM `countries` INNER JOIN `country_translations` 
    ON `country_translations`.`country_id` = `countries`.`id`

这会生成此SQL:

countries

这似乎是一个正确的查询,如果我在数据库控制台中运行它,它会获取我想要的数据。问题来了,因为我需要序列化SELECT `country_translations`.* FROM `country_translations` WHERE `country_translations`.`country_id` = 1 [["country_id", 1]] [...] SELECT `country_translations`.* FROM `country_translations` WHERE `country_translations`.`country_id` = 238 [["country_id", 238]] SELECT `country_translations`.* FROM `country_translations` WHERE `country_translations`.`country_id` = 239 [["country_id", 239]] 。它为每个国家/地区运行查询:

include

为了避免n + 1问题,我尝试countries = Country.select('countries.id, countries.short_code, country_translations.name').includes(:translations).joins(:translations) 查询翻译:

country

这就像一个魅力,只在一个查询中返回所有内容。问题是它从country_translationsSELECT countries.id, countries.short_code, country_translations.name, `countries`.`id` AS t0_r0, `countries`.`population` AS t0_r1, `countries`.`short_code` AS t0_r2, `countries`.`lat` AS t0_r3, `countries`.`lng` AS t0_r4, `countries`.`range` AS t0_r5, `countries`.`tilt` AS t0_r6, `countries`.`heading` AS t0_r7, `countries`.`country_code_short` AS t0_r8, `countries`.`date_format` AS t0_r9, ... `countries`.`created_at` AS t0_r12, `countries`.`updated_at` AS t0_r13, `country_translations`.`id` AS t1_r0, `country_translations`.`country_id` AS t1_r1, `country_translations`.`locale` AS t1_r2, `country_translations`.`created_at` AS t1_r3, `country_translations`.`updated_at` AS t1_r4, `country_translations`.`name` AS t1_r5, `country_translations`.`language` AS t1_r6, `country_translations`.`currency` AS t1_r7, `country_translations`.`capital` AS t1_r8, `country_translations`.`slug` AS t1_r9 FROM `countries` INNER JOIN `country_translations` ON `country_translations`.`country_id` = `countries`.`id` 获取了每个属性,忽略了select语句!

let chars = NSCharacterSet(charactersInString: "() \n")
text.componentsSeparatedByCharactersInSet(chars).joinWithSeparator("")

这带来了另一个问题,因为序列化对于这么多字段来说更复杂......

我错过了什么?我怎样才能得到我需要的那三个领域?

1 个答案:

答案 0 :(得分:1)

似乎您正在调用country.name并期望ActiveRecord结果中的name 属性,而globalize gem正在调用name < em>方法 - 触发n + 1。

使用ActiveRecord的includes方法是解决n + 1的一种方法,如你所提到的那样,但是会产生令人讨厌的副作用,即否定select语句并构建更大的ActiveRecord ::关系对象不是必需的。另外,您已经有效地选择了所需的字段。

AbM's comment以上指向解决方案;但是country_translations.name在您的查询中已经将name别名为countries = Country.select([ 'countries.id', 'countries.short_code', 'country_translations.name AS country_translation_name' ]) ,为了澄清,我建议如下:

countries

当迭代country.id # => 840 country.short_code # => "US" country.country_translation_name # => "United States of America" 时,您现在可以调用:

{{1}}