2009-06-17 18 views
7

Ứng dụng Rails của tôi đang bắt đầu cần các truy vấn phức tạp. Tôi có nên bắt đầu sử dụng các truy vấn SQL thô không? Xu hướng trong cộng đồng Rails là gì?Truy vấn Rails của tôi đang bắt đầu phức tạp, tôi có nên chuyển sang truy vấn SQL thô không? Bạn làm nghề gì?

Cập nhật: truy vấn

Tôi không có văn bản ngay bây giờ, tôi muốn hỏi câu hỏi này trước khi tôi bắt đầu. Nhưng đây là một ví dụ về những gì tôi muốn làm:

Tôi có các sách có danh mục. Tôi muốn say-

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 

tôi đã không viết các truy vấn được nêu ra nhưng tôi nghĩ rằng phiên bản ray sẽ là một cái gì đó như thế này:

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") 

tôi không nói ActiveRecord không thể xử lý truy vấn này , nhưng nó được chấp nhận hơn để đi với SQL nguyên cho dễ đọc (hoặc có thể có những hạn chế khác mà tôi chưa biết)?

+0

bạn có thể đưa ra một ví dụ cụ thể? –

+0

bạn có thể đưa ra một số ví dụ về các truy vấn mà bạn cảm thấy quá phức tạp khi sử dụng các tính năng của Rails/ActiveRecord không? – cpjolicoeur

+2

Xin lưu ý rằng loại nội suy đó thực sự là một ý tưởng tồi. Điều gì sẽ xảy ra nếu ngày1, ngày 2 hoặc ngày3 chứa ký tự "'"? Bạn đang ở trong một ngôn ngữ năng động; đó có thể là chuỗi. –

Trả lời

13

Ý tưởng chung là gắn các truy vấn-generated càng nhiều càng tốt và sử dụng các đoạn SQL chỉ khi cần thiết. Các đoạn SQL được hỗ trợ rõ ràng bởi vì những người sáng tạo của ActiveRecord nhận ra rằng SQL không thể được trừu tượng hoàn toàn.

Sử dụng phương pháp find không có đoạn SQL thường được thưởng bằng khả năng bảo trì tốt hơn. Với ví dụ của bạn, hãy thử:

Book.find(:all, 
    :conditions => ["created_at >= ? AND created_at <= ? AND updated_at <= ?", 
        date1, date2, date3] 
    :include => :carts) 

Các :inlude => :carts sẽ làm tham gia nếu bạn thêm has_many :carts để mô hình Book của bạn. Như bạn có thể thấy, không cần phải có nhiều SQL liên quan. Ngay cả việc trích dẫn và thoát của đầu vào có thể được để lại cho Rails, trong khi vẫn sử dụng SQL literals để xử lý các toán tử >=<=.

Đi thêm một chút, bạn có thể làm cho nó thậm chí còn rõ ràng hơn:

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) 

Cập nhật: điểm của named_scope s là, tất nhiên, để tái sử dụng các điều kiện. Đó là vào bạn để quyết định có hay không có ý nghĩa để đặt một tập hợp các điều kiện trong một phạm vi được đặt tên hay không.

+0

Những thứ rất hay. Mặc dù nếu tôi muốn tất cả các sách ngoại trừ những sách tồn tại trong giỏ hàng với delivery_date = hôm nay thì sao? tôi nghĩ rằng tôi muốn sử dụng lệnh giao nhau nhưng tôi gặp khó khăn khi tìm tài liệu cho việc này. bất kỳ trợ giúp hoặc liên kết nào sẽ là tuyệt vời – Tony

+1

Tôi nghĩ rằng đó là thời điểm bạn muốn nói ": condition => stuff" –

+0

Và/hoặc đi cho rằng, ngọt ngào tuyên bố công cụ của named_scope: deliver_today, lambda {: conditions => [" delivery_date <=? ", hôm nay]} Hoặc tôi có thể không tốt. Tùy chọn thứ hai đó thực sự có thể xảy ra, nhưng tôi vẫn mời bạn thử: P –

3

Giống như molf đang nói với: include, .find() có lợi thế là tải trẻ em háo hức. Ngoài ra, có một số plugin, như phân trang, sẽ bao hàm chức năng tìm kiếm. Bạn sẽ phải sử dụng .find() để sử dụng các plugin.

Nếu bạn có một truy vấn sql thực sự phức tạp, hãy nhớ rằng .find() sử dụng chuỗi tham số chính xác của bạn. Bạn luôn có thể đưa mã sql của riêng bạn:

: conditions => [ "id trong đoàn (select * from bảng ...

Và đừng quên có rất nhiều các thông số tùy chọn cho.find()

  • : điều kiện - Đoạn SQL như "administrator = 1", ["user_name =?", tên người dùng] hoặc ["user_name =: user_name", {: user_name => user_name}]. Xem các điều kiện trong phần giới thiệu.
  • : thứ tự - Một đoạn SQL như "created_at DESC, name".
  • : nhóm - Tên thuộc tính mà kết quả sẽ được nhóm lại. Sử dụng mệnh đề SQL BY GROUP.
  • : có - Kết hợp với +: nhóm + mục này có thể được sử dụng để lọc các bản ghi mà GROUP BY trả về. Sử dụng mệnh đề SQL HAVING.
  • : giới hạn - Số nguyên xác định giới hạn về số hàng cần được trả về.
  • : bù đắp - Một số nguyên xác định bù trừ từ nơi các hàng sẽ được tìm nạp. Vì vậy, tại 5, nó sẽ bỏ qua các hàng từ 0 đến 4.
  • : tham gia - Hoặc là một đoạn SQL cho các phép nối bổ sung như "TÌM KIẾM THAM GIA nhận xét TRÊN bình luận.post_id = id" (hiếm khi cần), liên kết được đặt tên trong cùng một biểu mẫu được sử dụng cho tùy chọn: include, sẽ thực hiện INNER JOIN trên (các) bảng được liên kết hoặc một mảng chứa hỗn hợp của cả hai chuỗi và các liên kết được đặt tên. Nếu giá trị là một chuỗi, thì các bản ghi sẽ được trả về chỉ đọc vì chúng sẽ có các thuộc tính không tương ứng với các cột của bảng. Pass: readonly => false để ghi đè.
  • : bao gồm - Các liên kết tên cần được tải cùng. Các ký hiệu có tên là các liên kết đã được xác định. Xem tải mong muốn theo Hiệp hội.
  • : chọn - Theo mặc định, đây là "*" như trong "CHỌN * TỪ", nhưng có thể thay đổi nếu bạn, ví dụ: muốn tham gia nhưng không bao gồm các cột đã tham gia. Lấy một chuỗi có đoạn SQL SELECT (ví dụ: "id, name").
  • : từ - Theo mặc định, đây là tên bảng của lớp, nhưng có thể được thay đổi thành tên bảng thay thế (hoặc thậm chí tên của chế độ xem cơ sở dữ liệu).
  • : chỉ đọc - Đánh dấu các bản ghi đã trả về chỉ đọc để chúng không thể được lưu hoặc cập nhật.
  • : khóa - Một đoạn SQL như "FOR UPDATE" hoặc "LOCK IN SHARE MODE". : lock => true cung cấp khóa độc quyền mặc định của kết nối, thường là "FOR UPDATE".

src: http://api.rubyonrails.org/classes/ActiveRecord/Base.html#M002553

+0

Ai đó chỉnh sửa thông tin này để các thông số dễ đọc hơn. –

Các vấn đề liên quan