My Rails应用程序开始需要复杂的查询。我应该开始使用原始SQL查询吗? Rails社区的趋势是什么?
更新:
我现在没有书面查询,我想在开始之前先问这个问题。但这是我想要做的一个例子:
我的书有类别。我想说 -
Give me all books that were:
-created_at (added to store) between date1 and date2
-updated_at before date3
-joined with books that exist in shopping carts right now
我还没有编写查询,但我认为rails版本将是这样的:
books_to_consider = Book.find(:all,
:conditions => "created_at <= '#{date2}' AND created_at >= '#{date1}' AND updated_at <= '#{date3}'",
:joins => "as b inner join carts as c on c.book_id = b.id")
我并不是说ActiveRecord无法处理这个查询,但是为了便于阅读可以接受原始SQL(或者还有其他我不知道的限制)?
答案 0 :(得分:13)
一般的想法是尽可能坚持ActiveRecord
- 生成的查询,并仅在必要时使用SQL片段 。显式支持SQL片段,因为ActiveRecord
的创建者意识到SQL无法完全抽象出来。
使用不带SQL片段的find
方法通常会获得更好的可维护性。举个例子,试试:
Book.find(:all,
:conditions => ["created_at >= ? AND created_at <= ? AND updated_at <= ?",
date1, date2, date3]
:include => :carts)
如果您将:inlude => :carts
添加到has_many :carts
模型,则Book
会进行加入。正如您所看到的,不必涉及太多SQL。即使输入的引用和转义也可以留给Rails,同时仍然使用SQL文字来处理>=
和<=
运算符。
更进一步,你可以让它更清晰:
class Book < AciveRecord::Base
# Somewhere in your Book model:
named_scope :created_between, lambda { |start_date, end_date|
{ :conditions => { :created_at => start_date..end_date } }
}
named_scope :updated_before, lambda { |date|
{ :conditions => ["updated_at <= ?", date] }
}
# ...
end
Book.created_between(date1, date2).updated_before(date3).find(:all,
:include => :carts)
更新: named_scope
s的重点当然是重用条件。您可以自行决定是否将一组条件置于命名范围内是否有意义。
答案 1 :(得分:3)
就像molf所说:include,.find()具有急切加载孩子的优势。 此外,有几个插件,如分页,将包装查找功能。你必须使用.find()来使用插件。
如果你有一个非常复杂的SQL查询,请记住.find()使用你的确切参数字符串。你总是可以注入自己的sql代码:
:conditions =&gt; [“id in union(select * from table ...
不要忘记.find()
有很多可选参数src:http://api.rubyonrails.org/classes/ActiveRecord/Base.html#M002553