简体   繁体   English

带有ID联接的Rails 3 Active Record查询接口的问题

[英]Problems with Rails 3 Active Record Query Interface with join on ID

I have been having a problem with the Rails 3 Active Record Query Interface. 我一直在与Rails 3活动记录查询接口有问题。 I have a lookup table (lookups), a Main table (through_references), and a through/join table called through_tables. 我有一个查找表(lookups),一个主表(through_references)和一个通过/联接表through_tables。 Thus this is a HABTM configuration that I have set up using has_many :through. 因此,这是我使用has_many:through设置的HABTM配置。

Update: Of special note here is that when I am doing these joins, I have been joining on IDs, to provide filtering of records. 更新:这里要特别注意的是,当我执行这些联接时,我一直在联接ID,以提供记录过滤。 It seems that this does not work with Active Record Query Interface. 看来这不适用于Active Record查询接口。 If you do not want to see the gory details of my travails, you can skip down to see my workaround below. 如果您不想查看我的工作的血腥细节,可以跳到下面查看我的解决方法。

We are also going to have a number of Main Items (through_references table) should be able to have any combination of lookup items, and to conveniently be able to click the relevant lookup items say through check boxes. 我们还将有许多主要项(through_references表)应该可以具有查找项的任意组合,并可以方便地单击相关的查找项,例如复选框。

I have posted the code on github . 我已将代码发布在github上 There is quite a lot more explanations on the github source code. github源代码上有很多解释。 to see the results, go to the lookups index page. 要查看结果,请转到查找索引页面。 Note that you will need to create the records using the scaffold code. 请注意,您将需要使用脚手架代码创建记录。

I also have the code up and running on heroku , with more explanations and examples. 我还拥有在heroku上运行的代码,以及更多的解释和示例。

class Lookup < ActiveRecord::Base
  has_many :fk_references
  has_many :through_tables
  has_many :through_references, :through => :through_tables
  attr_accessible :name, :value
end

class ThroughTable < ActiveRecord::Base
  belongs_to :through_reference
  belongs_to :lookup
  attr_accessible :description, :through_reference_id, :lookup_id
end

class ThroughReference < ActiveRecord::Base
  has_many :through_tables
  has_many :lookups, :through => :through_tables
  attr_accessible :description
end

If we want to have a listing if all the lookup items, and the Main Items that correspond with them, we can LEFT JOIN the 'lookups' table with the Main Items (through_references) table. 如果我们想列出所有查找项目以及与之对应的主要项目,则可以将“查找”表与主要项目(through_references)表一起加入。 Corresponding SQL: 对应的SQL:

SELECT * FROM lookups
  LEFT OUTER JOIN through_tables ON (lookups.id = through_tables.lookup_id AND through_tables.through_reference_id = 1)
  LEFT OUTER JOIN through_references ON through_references.id = through_tables.through_reference_id
  ORDER BY lookups.id

Returned records: 返回记录:

1;“Lookup Item 1”;“1”;“2012-06-06 17:14:40.819791”;“2012-06-06 17:14:40.819791”;1;1;1;“Main Item 1 has Lookup item 1”;“2012-06-06 17:17:31.355425”;“2012-06-06 17:17:31.355425”;1;“Main Item 1”;“2012-06-06 17:16:30.004375”;“2012-06-06 17:16:30.004375”

2;“Lookup Item 2”;“2”;“2012-06-06 17:14:59.584756”;“2012-06-06 17:14:59.584756”;;;;“”;“”;“”;;“”;“”;“”

3;“Lookup Item 3”;“3”;“2012-06-06 17:15:14.700239”;“2012-06-06 17:15:14.700239”;2;1;3;“Main Item 1 has Lookup item 3”;“2012-06-06 17:17:53.169715”;“2012-06-06 17:17:53.169715”;1;“Main Item 1”;“2012-06-06 17:16:30.004375”;“2012-06-06 17:16:30.004375”

This is what I expected. 这是我所期望的。

=== Active Record Query Interface using custom left join ===使用自定义左联接的Active Record查询接口

Lookup.joins(“LEFT OUTER JOIN through_tables ON (lookups.id = through_tables.lookup_id AND through_tables.through_reference_id = 1)” ).includes(:through_references).order(‘lookups.id’)

What is returned from Active Record Query Interface (note I navigate down through the Active Record hierarchy): 从Active Record查询界面返回的内容(请注意,我向下浏览Active Record层次结构):

Lookup ID Lookup Name Lookup Value Through Table ID Through Table Description Main Item ID Main Item Description
1 Lookup Item 1 1 1 Main Item 1 has Lookup item 1 1 Main Item 1
1 Lookup Item 1 1 3 Main Item 2 has Lookup item 1 2 Main Item 2
2 Lookup Item 2 2 4 Main Item 2 has Lookup item 2 2 Main Item 2
3 Lookup Item 3 3 2 Main Item 1 has Lookup item 3 1 Main Item 1

This is NOT what I expected. 这不是我所期望的。

What we have here is identical to the simple left join (without the AND clause). 我们这里拥有的内容与简单的左连接(没有AND子句)相同。 This tells me that the AND clause is being ignored in the Active Record Query Interface. 这告诉我在Active Record查询接口中AND子句被忽略。

=== Active Record Query Interface using find_by_sql approach ===使用find_by_sql方法的活动记录查询接口

Lookup.find_by_sql("SELECT * FROM lookups LEFT OUTER JOIN through_tables ON (through_tables.lookup_id = lookups.id AND through_tables.through_reference_id = 1) LEFT OUTER JOIN through_references ON through_references.id = through_tables.through_reference_id ORDER BY lookups.value, through_references.id" )

What is returned from Active Record Query Interface (note I navigate down through the Active Record hierarchy):: 从Active Record查询界面返回的内容(请注意,我向下浏览Active Record层次结构):

Lookup ID   Lookup Name     Lookup Value    Through Table ID    Through Table Description   Main Item ID    Main Item Description
1   Lookup Item 1   1   3   Main Item 2 has Lookup item 1   2   Main Item 2
1   Lookup Item 1   1   1   Main Item 1 has Lookup item 1   1   Main Item 1
    Lookup Item 2   2   No through_tables entry
1   Lookup Item 3   3   3   Main Item 2 has Lookup item 1   2   Main Item 2
1   Lookup Item 3   3   1   Main Item 1 has Lookup item 1   1   Main Item 1

The results here are crazy! 这里的结果太疯狂了!

Is this a BUG, is this the intended effects, or am I missing something ? 这是一个错误,是预期的效果,还是我缺少了什么?

I hope there is a clean way of doing this, without having to generate two result sets, and merge them by code. 我希望有一个干净的方法,而不必生成两个结果集,并通过代码合并它们。

I have found a work-around. 我找到了一种解决方法。 The issue seems to be that Active Record will not recognize joins that filter on an ID (LEFT OUTER JOIN xyz ON xyz.id = ID). 问题似乎是Active Record无法识别对ID进行过滤的联接(LEFT OUTER JOIN xyz ON xyz.id = ID)。

My work-around involves creating a stored procedure or function that takes the ID in as a parameter, does the join in the Database, and returns a nice flat recordset. 我的变通办法涉及创建一个存储过程或函数,该过程将ID作为参数,在数据库中进行联接,并返回一个不错的平面记录集。

see: Heroku demo page (skip to bottom) 请参阅: Heroku演示页面(跳到底部)

Note, I am not marking this as a solution, because this is a work-around, and nothing to do with active record. 请注意,我没有将其标记为解决方案,因为这是一种变通方法,并且与活动记录无关。

Well, reading the github project, I see this: 好吧,阅读github项目,我看到了:

What I really want to do is have a list of all of the lookup items, and if there are matching Main Items, have them appended on to the returned record, and if not, I want nulls. 我真正想做的是拥有所有查找项目的列表,如果有匹配的Main Items,请将它们附加到返回的记录上,否则,我希望为null。 This is a technique that I have used for over 10 years. 这是我使用了10多年的技术。

I'm thinking that problem is exactly that you want to do it that way, when it would be more natural to let rails eager loading handle it, and so you've gotten fixated on fetching everything in a single massive join. 我在想这个问题恰恰是您想要这样做,那时候让渴望加载的Rails处理它会更自然,因此您已经将注意力集中在通过单个大规模连接获取所有内容上。

What I would do is something like: 我要做的是这样的:

Lookup.where( .. insert any needed conditions here ...).includes(:through_tables) Lookup.where(..在此处插入任何需要的条件...)。includes(:through_tables)

Then ActiveQuery will then fetch all the Lookup in one query, and then use eager loading to fetch any associations named in the includes statement, one query per association. 然后,ActiveQuery将在一个查询中获取所有Lookup,然后使用预先加载来获取包含语句中命名的任何关联,每个关联一个查询。

Note I'm not saying that joins are bad, just saying that this is a more natural way to do it in rails. 请注意,我并不是说联接是不好的,只是说这是在Rails中进行连接的更自然的方法。 I like to use the Preloader http://apidock.com/rails/ActiveRecord/Associations/Preloader to separate out the decision about what to eager load from the decision about which data to fetch. 我喜欢使用Preloader http://apidock.com/rails/ActiveRecord/Associations/Preloader将需要加载哪些内容的决定与要获取哪些数据的决定区分开来。 I find that helpful in controllers - let the model decide what the conditions are, but let the controller decide which objects it'll need to eager load. 我发现这对控制器很有帮助-让模型决定条件是什么,但让控制器决定需要加载哪些对象。

HTH 高温超导

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

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