ActiveRecord 中多态关联的热切加载
这是我第一次使用 Rails,我想知道是否可以在一个 SQL 查询中加载一个多态关联?它们之间的模型和关联足够基本:资产模型/表可以通过多态关联引用内容(图像、文本或音频),即
class Asset < ActiveRecord::Base :belongs_to :content, :polymorphic => true end
图像、文本、音频的定义如下:
class Image < ActiveRecord::Base :has_one :asset, :as => :content end
当我尝试加载图像,如下所示:
Image.first( :conditions => {:id => id}, :include => :asset )
它指定两个查询,一个用于检索图像,另一个用于检索资产(仅供参考,如果我指定 :joins
也会发生这种情况)。根据我的理解,ActiveRecord 这样做是因为它不知道 Image 和 Asset 之间存在一对一的关联。有没有一种方法可以强制连接并一次性检索 2 个对象?我也尝试过使用 join 和自定义选择,但最终我不得不手动创建 ActiveRecord 模型及其关联。
ActiveRecord 是否提供了执行此操作的方法?
This is my first time using Rails and I was wondering if it's possible to load a has one polymorphic association in one SQL query? The models and associations between them are basic enough: An Asset model/table can refer to a content (either an Image, Text, or Audio) through a polymorphic association, i.e.
class Asset < ActiveRecord::Base :belongs_to :content, :polymorphic => true end
and the Image, Text, Audio are defined like this:
class Image < ActiveRecord::Base :has_one :asset, :as => :content end
When I try to load an Image, say like this:
Image.first( :conditions => {:id => id}, :include => :asset )
It specifies two queries, one to retrieve the Image and another to retrieve the Asset (FYI, this happens also if I specify a :joins
). Based on my understanding, ActiveRecord does this because it doesn't know there's a one-to-one association between Image and Asset. Is there a way to force a join and retrieve the 2 objects in one go? I've also tried using join with a custom select, but I end up having to create the ActiveRecord models manually and their associations.
Does ActiveRecord provide a way to do this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在深入研究 Rails 源代码后,我发现您可以通过在 select、conditions 或 order 子句中引用当前模型以外的表来强制连接。
因此,如果我在 Asset 表上指定一个顺序:
生成的 SQL 将使用左外连接并将所有内容都放在一个语句中。我更喜欢内部联接,但我想现在就可以了。
After digging through the Rails source I've discovered that you can force a join by referencing a table other than the current model in either the select, conditions or order clauses.
So, if I specify an order on the Asset table:
The resulting SQL will use a left outer join and everything in one statement. I would have preferred an inner join, but I guess this will do for now.
我自己也遇到过这个问题。 ActiveRecord 更倾向于让 Rubyists(他们甚至可能不太熟悉 SQL)轻松地与数据库交互,而不是优化数据库调用。您可能必须与较低级别的数据库(例如 DBI)进行交互才能提高性能。使用 ActiveRecord 肯定会影响您设计架构的方式。
对 SQL 效率的渴望让我考虑使用其他 ORM。我还没有找到适合我需要的。即使那些更倾向于事务 SQL 本身的应用程序(例如 Sequel)也有大量的 Ruby API。如果没有类似 Ruby 的 API,只需手动编写 T-SQL,我就会感到满意。我所追求的 ORM 的真正好处是 M,将(一个或多个表的)结果集映射到对象中。
I ran up against this issue myself. ActiveRecord leans more toward the end of making it easy for Rubyists (who may not even be all too familiar with SQL) to interface with the database, than it does with optimized database calls. You might have to interact with the database at a lower level (e.g. DBI) to improve your performance. Using ActiveRecord will definitely affect how you design your schema.
The desire for SQL efficiency got me thinking about using other ORMs. I haven't found one to suit my needs. Even those that move more toward transact SQL itself (e.g. Sequel) have a heavy Ruby API. I would be content without a Ruby-like API and just manually writing my T-SQL. The real benefit I'm after with an ORM is the M, mapping the result set (of one or more tables) into the objects.
(这是针对 Rails 3 语法的。)
MetaWhere 是一个很棒的 gem,可以让 ActiveRecord 常用域之外的复杂查询变得简单且像 ruby 一样。 (@wayne:它也支持外部联接。)
https://github.com/ernie/meta_where
多态连接有点棘手。以下是我使用 MetaWhere 的方法:
事实上,我在我的多态关联类中做了一个方便的方法:
所以它总是会查询 & 。急切加载特定类型的资产。我还没有尝试在一个查询中将其与多种类型的联接混合。由于多态性使用相同的外键来引用不同的表,因此在 SQL 级别上,您必须将其指定为单独的联接,因为一个联接仅联接到一张表。
这仅适用于 ActiveRecord 3,因为您可以使用 AREL 的惊人功能。
(This is for Rails 3 syntax.)
MetaWhere is an awesome gem for making complex queries that are outside of ActiveRecord's usual domain easy and ruby-like. (@wayne: It supports outer joins as well.)
https://github.com/ernie/meta_where
Polymorphic joins are a little trickier. Here's how I did mine with MetaWhere:
In fact, I made a convenience method in my polymorphic-association-having class:
So it will always query & eager load a particular type of asset. I haven't tried mixing it with multiple types of join in one query. Because polymorphism works using the same foreign key to reference different tables, on the SQL level you have to specify it as separate joins because one join only joins to one table.
This only works with ActiveRecord 3 because you have access to the amazing power of AREL.