【问题标题】:Rails: query for 2-step relation through join-table + has many relationRails:通过连接表查询两步关系+有很多关系
【发布时间】:2019-05-24 21:41:51
【问题描述】:

我正在努力改进我的数据库方案。目前,我使用 has_many through 结构,其中包含土地模型/表、运输服务模型/表和连接土地和运输表的 postzone 模型/表。

我可以这样查询:

@shippingservices = @cart.available_shipping_services.includes(:lands, :postzones).where('postzones.land_id = ?', params[:id])

并获得给定土地(国家)的所有运输服务。

但是这样我最终会在 postzone 表中重复很多,并且维护非常困难。如果我可以在有许多土地的区域收集土地,而不是将航运服务连接到一个区域,那会容易得多。就像在这个方案中一样:

在这种情况下,我将如何查询给定土地的所有运输服务?

对于连接表,我会执行以下操作:

@shippingservices = @cart.available_shipping_services.joins(:lands => :zones).where('lands_zones_join.land_id = ?', params[:id])

这不起作用,因为我得到:

Mysql::Error: Unknown column 'lands_zones_join.zone_id' in 'where clause': SELECT `shippingservices`.* FROM `shippingservices` 
INNER JOIN `zones` ON `zones`.`id` = `shippingservices`.`zone_id` 
INNER JOIN `lands_zones` ON `lands_zones`.`zone_id` = `zones`.`id` 
INNER JOIN `lands` ON `lands`.`id` = `lands_zones`.`land_id` 
INNER JOIN `lands_zones` `zones_lands_join` ON `zones_lands_join`.`land_id` = `lands`.`id` 
INNER JOIN `zones` `zones_lands` ON `zones_lands`.`id` = `zones_lands_join`.`zone_id` 
WHERE (weightmin <= 50 AND weightmax >= 50 AND height >= 3 AND shippingservices.shippingcarrier = '1') AND (length >= 210 AND width >= 149) AND (lands_zones_join.zone_id = '2')

这可能吗?我怎样才能让它工作?

提前谢谢你!

更新

models/shippingservices.rb

class Shippingservice < ActiveRecord::Base
  belongs_to :zone
  has_many :lands, :through => :zone
end

app/models/zone.rb

class Zone < ActiveRecord::Base
  has_and_belongs_to_many :lands, :join_table => "lands_zones"
  has_many :shippingservices
end

app/models/landszone.rb

class LandsZone < ActiveRecord::Base
  belongs_to :land
  belongs_to :zone
end

app/models/land.rb

class Land < ActiveRecord::Base
  has_and_belongs_to_many :zones, :join_table => "lands_zones"
  has_many :shippingservices, :through => :zones
end

db/schema.rb

create_table "lands", :force => true do |t|
  t.string   "name"
end

create_table "lands_zones", :force => true do |t|
  t.integer  "land_id"
  t.integer  "zone_id"
end

add_index "lands_zones", ["land_id"], :name => "index_lands_zones_on_land_id"
add_index "lands_zones", ["zone_id"], :name => "index_lands_zones_on_zone_id"

create_table "shippingservices", :force => true do |t|
  t.integer  "zone_id"
  t.string   "name"
  t.string   "shippingcarrier"
end

  create_table "zones", :force => true do |t|
    t.string   "name"
  end

我通过删除时间戳等来减少它,但保留了所有必要的部分。

【问题讨论】:

  • 你能从每个模型和你的 schema.rb 中添加实际代码吗?我怀疑连接表被命名为lands_zones 而不是lands_zones_join
  • @Tom 感谢您的反馈。我添加了您要求的所有数据。尽管我使用了多年以来使用的相同模式 + 查询,但仅用于连接表而不用于连接表 + 有很多通过。
  • .where('lands_zones_join.land_id = ?', params[:id]) 为什么要在这里查询名为land_zones_join 的表? .where('lands_zones.land_id = ?', params[:id]) 架构和模型看起来正确。
  • 我使用.where('lands_zones_join.land_id = ?', params[:id]) 进行具有相同模型和架构配置的连接连接,并且它有效。目前这些协会已经存在,但我最终会在给定的土地上获得双倍的运输服务。
  • 我以前从未见过在查询中将_join 添加到表名的末尾。你可以试试@cart.available_shipping_services.joins(:lands).where(lands: {id: params[:id]})吗?

标签: mysql ruby-on-rails ruby-on-rails-3 activerecord


【解决方案1】:

@shippingservices = @cart.available_shipping_services.joins(:lands =&gt; :zones).where('lands_zones_join.land_id = ?', params[:id])

where 子句中的lands_zones_join 表不正确。 Rails 将其视为派生表名,并应用此处所示的两个额外连接:

INNER JOIN `lands_zones` `zones_lands_join` ON `zones_lands_join`.`land_id` = `lands`.`id` 
INNER JOIN `zones` `zones_lands` ON `zones_lands`.`id` = `zones_lands_join`.`zone_id`

这会导致查询结果重复。

ShippingserviceLand 的关系已在模型和架构中正确设置。因此,我们可以直接连接这些表并查询 lands 表本身的 id:

@cart.available_shipping_services.joins(:lands).where(lands: {id: params[:id]})

【讨论】:

  • 当我在会话中时,我必须如何在查询中定义land_id?我发现查询在一个方向上工作,但在返回 bowser 时不会保留选择。我在这里描述了一切:stackoverflow.com/questions/53953658/…也许你可以指出我正确的方向。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-28
  • 1970-01-01
  • 1970-01-01
  • 2011-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多