Một vài vấn đề về Active Record Associations



  • Trong Rails, association là một kết nối giữa hai Active Record models. Chúng ta sử dụng association giữa hai models để làm các hàm, các biểu thức, phép tính trong code trở lên đơn giản hơn.

    1. Các loại quan hệ

    Rails support 6 loại quan hệ:

    • belongs_to
    • has_one
    • has_many
    • has_many :through
    • has_one :through
    • has_and_belongs_to_many

    1.1 belongs_to

    belongs_to là quan hệ một - một giữa 2 model, sao cho mỗi cá thể của model này thuộc về 1 cá thể của model kia.
    Ví dụ chúng ta có 2 model là Author và Book. Mỗi book thuộc về 1 author. Trong model Book ta sẽ khai báo:

    class Book < ApplicationRecord
      belongs_to :author
    end
    

    ! Chú ý khi khai báo belongs_to phải sử dụng từ số ít.

    1.2 has_one

    has_one cũng là quan hệ một - một, nhưng về ngữ nghĩa sẽ ngược với belongs_to về model sở hữu và bị sở hữu.
    Ví dụ 1 supplier có 1 account:

    class Supplier < ApplicationRecord
      has_one :account
    end
    

    1.3 has_many

    has_many là quan hệ một - nhiều với model. Nó thường đi kèm với quan hệ belongs_to ở phía model kia. Nó chỉ ra 1 cá thể của model này có thể không có hoặc có nhiều cá thể của model kia.
    Ví dụ 1 author có thể có nhiều book.

    class Author < ApplicationRecord
      has_many :books
    end
    

    ! Chú ý khi khai báo has_many cần sử dụng từ dạng số nhiều.

    1.4 has_many :through

    has_many :through thường xuyên được sử dụng để tạo quan hệ nhiều - nhiều với model khác. Nó cho phép 1 cá thể của model này liên kết với nhiều cá thể của model khác thông qua một model thứ 3.
    Ví dụ trong một buổi khám sức khỏe tổng quát. Mỗi bệnh nhân (patient) sẽ lần lượt xếp hàng để đợi đến những lượt khám (appointment) để gặp các bác sĩ (physician). Như vậy mỗi lượt khám, 1 bệnh nhân sẽ gặp 1 bác sĩ. Như vậy cả buổi khám, 1 bênh nhân sẽ gặp nhiều bác sĩ và 1 bác sĩ sẽ khám cho nhiều bệnh nhân.

    
    class Physician < ApplicationRecord
      has_many :appointments
      has_many :patients, through: :appointments
    end
     
    class Appointment < ApplicationRecord
      belongs_to :physician
      belongs_to :patient
    end
     
    class Patient < ApplicationRecord
      has_many :appointments
      has_many :physicians, through: :appointments
    end
    

    has_many :through cũng có thể dùng để tạo quan hệ has_many lồng nhau.
    Ví dụ mỗi document có nhiều section, mỗi section lại có nhiều paragraph.

    class Document < ApplicationRecord
      has_many :sections
      has_many :paragraphs, through: :sections
    end
     
    class Section < ApplicationRecord
      belongs_to :document
      has_many :paragraphs
    end
     
    class Paragraph < ApplicationRecord
      belongs_to :section
    end
    

    1.5 has_one :through

    Đây là quan hệ một - một. Nó chỉ ra 1 cá thể của model này liên kết với 1 cá thể của model khác thông qua một model thứ 3.
    Ví dụ:

    class Supplier < ApplicationRecord
      has_one :account
      has_one :account_history, through: :account
    end
     
    class Account < ApplicationRecord
      belongs_to :supplier
      has_one :account_history
    end
     
    class AccountHistory < ApplicationRecord
      belongs_to :account
    end
    

    1.6 has_and_belongs_to_many

    has_and_belongs_to_many là quan hệ nhiều - nhiều.
    Ví dụ:

    class Assembly < ApplicationRecord
      has_and_belongs_to_many :parts
    end
     
    class Part < ApplicationRecord
      has_and_belongs_to_many :assemblies
    end
    

    ! Tuy không cần khai báo model phụ của 2 model này những vẫn cần tạo assemblies_parts.

    2. Lựa chọn giữa belongs_to và has_one

    Khi xây dựng quan hệ một - một ta cần thêm belongs_to vào một model và has_one vào một model. Vậy làm cách nào ta biết thêm cái nào vào đâu.
    Nếu đã có sẵn cơ sở dữ liệu thì ta sẽ dựa vào khóa ngoài (foreign key), nó nằm ở bảng nào thì model đó sẽ đặt quan hệ belongs_to. Tuy nhiêu khi cần xây dựng cơ sở dữ liệu thì ta cần dự vào ý nghĩa thực tế để xác định.
    Ví dụ với 2 thứ là Người và Tên. Theo đúng ý nghĩa thì mỗi người có một (has_one) tên, và mỗi tên thuộc về (belongs_to) một người.

    3. Lựa chọn giữa has_many :through và has_and_belongs_to_many

    Đây đều là quan hệ nhiều nhiều.

    Với has_and_belongs_to_many

    class Assembly < ApplicationRecord
      has_and_belongs_to_many :parts
    end
     
    class Part < ApplicationRecord
      has_and_belongs_to_many :assemblies
    end
    

    Với has_many :through

    class Assembly < ApplicationRecord
      has_many :manifests
      has_many :parts, through: :manifests
    end
     
    class Manifest < ApplicationRecord
      belongs_to :assembly
      belongs_to :part
    end
     
    class Part < ApplicationRecord
      has_many :manifests
      has_many :assemblies, through: :manifests
    end
    

    Để lựa chọn, đơn giản nhất là dựa vào ứng dụng của model quan hệ thứ 3. Nếu nó chỉ đơn thuần để liên kết 2 model chính và không còn tác dụng gì khác thì ta nên dùng has_and_belongs_to_many, còn nếu ta cần sử dụng nó vào nhiều mục đích khác thì nên dùng has_many :through

    4. Controlling Caching

    Tất cả các association methods đều được xây dựng xung quang bộ nhớ đệm, cái mà sẽ giữ kết quả của lần query gần nhất cho những tính toán tương tự về sau. Cache có thể chia sẽ giữa các hàm trong controller.
    Ví dụ:

    author.books                    # lấy ra books từ trong cơ sở dữ liệu
    author.books.size            # sử dụng lại books đã lưu cache
    author.books.empty?      # sử dụng lại books đã lưu cache
    

    Nếu bán muốn reload cache vì có thể dữ liệu đã bị thay đổi ở chỗ nào đó thì bạn có thể dùng hàm reload.

    author.books                                # lấy ra books từ trong cơ sở dữ liệu
    author.books.size                        # sử dụng lại books đã lưu cache
    author.books.reload.empty?     # loại bỏ cache đã lưu books và lấy ra lại từ cơ sở dữ liệu
    

    Nguồn: Viblo


Hãy đăng nhập để trả lời
 

Có vẻ như bạn đã mất kết nối tới LaptrinhX, vui lòng đợi một lúc để chúng tôi thử kết nối lại.