Bảng không có lớp có thể với Datamapper?


8

Tôi có một lớp Item với các thuộc tính sau:

itemId,name,weight,volume,price,required_skills,required_items.

Vì hai thuộc tính cuối cùng sẽ được đa trị hóa, tôi đã loại bỏ chúng và tạo các lược đồ mới như:

itemID,required_skill( itemIDlà khóa ngoại, itemID and required_skilllà khóa chính.)

Bây giờ, tôi bối rối làm thế nào để tạo / sử dụng bảng mới này. Dưới đây là các tùy chọn xuất hiện trong tâm trí của tôi:

1) Mối quan hệ giữa Item và required_skills là một-nhiều, vì vậy tôi có thể tạo một lớp requiredSkill, thuộc về Item, đối với Item, trong đó lần lượt có n RequestSkills. Sau đó tôi có thể làm Item.get(1).requiredskills. Điều này nghe có vẻ hợp lý nhất với tôi và cung cấp cho tôi các phương thức và truy vấn như:

sugar.components.create :raw_material => water.name
sugar.components.create :raw_material => sugarcane.name
sugar.components
sugar.components.count

2) Vì required_skills có thể được coi là hằng số (vì chúng giống với quy tắc), tôi có thể đặt chúng vào cơ sở dữ liệu băm hoặc gdbm hoặc bảng sql khác và truy vấn từ đó, mà tôi không thích.

Câu hỏi của tôi là: có cái gì đó giống như bảng modelless trong datamapper, trong đó datamapper chịu trách nhiệm từ việc tạo và tính toàn vẹn của bảng và cho phép tôi truy vấn nó theo cách datamapper, nhưng không yêu cầu một lớp, như tôi có thể làm nó trong sql ?

Tôi đã giải quyết vấn đề của mình bằng cách sử dụng cách đầu tiên: Tôi đã tạo một lớp mới cho mỗi quy trình chuẩn hóa (xuất hiện dưới dạng liên kết một-nhiều ở trên). Tuy nhiên, tôi chưa quen với lập trình hướng đối tượng và tôi không biết liệu việc tạo một lớp mới cho mỗi chuẩn hóa như vậy có phải là cách thông thường để thực hiện trong datamapper hay đúng hơn là hack? Điều này, và liệu có cách nào tốt hơn để làm điều này, là những gì tôi muốn biết.

@JustinC

Đọc lại các Hiệp hội datamapper.org nhiều lần, bây giờ tôi thấy rằng datamapper chắc chắn yêu cầu các lớp riêng biệt để tham gia. Vì vậy, bạn đã trả lời câu hỏi của tôi. Tuy nhiên, kể từ khi Robert Harvey đặt tiền thưởng, tôi cảm thấy có trách nhiệm phải chờ thêm một chút để có phản hồi về một cách năng động.

Mã của bạn phàn nàn với Cannot find the child_model Container for Item in containers. Tôi đã quản lý để làm cho nó hoạt động với ví dụ thứ hai về liên kết tự giới thiệu như bên dưới (đặt ở đây làm tài liệu tham khảo cho người khác):

class Item
  class Link
    include DataMapper::Resource
    storage_names[:default] = "requirement_links"

    belongs_to :require, "Item", :key => true
    belongs_to :required, "Item", :key => true
  end

  include DataMapper::Resource

  property :id, Serial
  property :name, String, :required => true

  has n, :links_to_required_items, "Item::Link", :child_key => [:require_id]
  has n, :links_to_requiring_items, "Item::Link", :child_key => [:required_id]

  has n, :required_items, self,
    :through => :links_to_required_items,
    :via => :required
  has n, :requiring_items, self,
    :through => :links_to_requiring_items,
    :via => :require

 def require(others)
    required_items.concat(Array(others))
    save
    self
  end

  def unrequire(others)
    links_to_required_items.all(:required => Array(others)).destroy!
    reload
    self
  end
end

Vì vậy, tôi có thể làm:

jelly = Item.get :name => "Jelly"
sugar = Item.get :name => "Sugar"
jelly.require sugar

để yêu cầu các mặt hàng và:

jelly.required_items.each { |i|; puts i.name }

để liệt kê các yêu cầu, đó là thực sự tuyệt vời.

Sau khi đọc câu trả lời của bạn, tôi thấy rằng tôi vẫn chưa bình thường hóa lược đồ cơ sở dữ liệu của mình hơn nữa. Thành thật mà nói, tôi không thấy quan điểm xác định mối quan hệ giữa nguyên liệu thô và sản phẩm là tự tham khảo. Ý tôi là, nếu đó là một chương trình nhỏ, tôi chắc chắn sẽ sử dụng hàm băm {:jelly => ":sugar => 3, :water => 5"}để phản ánh các mục và số lượng cần thiết, theo nguyên tắc YAGNI. Làm như trong tùy chọn 1 đã cung cấp cho tôi các truy vấn và phương thức đơn giản như các truy vấn được cung cấp bởi hiệp hội tự giới thiệu. (Tuy nhiên, tôi phải thừa nhận rằng nó trông giống một thủ tục được lưu trữ hơn là một cuộc gọi phương thức đến một đối tượng.)

Vì vậy, bạn có thể rất bận tâm để giải thích những lợi ích của việc sử dụng một hiệp hội tự giới thiệu, rất khó hiểu / thực hiện đối với tôi, so với cách tiếp cận đơn giản hơn của tôi? Tôi chưa quen với OOP và tự hỏi liệu tôi có bị hạ thấp không.

Câu trả lời:


2

Tôi nghĩ rằng những gì bạn đang tìm kiếm ở cấp độ khái niệm SQL là một bảng nối (bản đồ, liên kết, trình phân giải, trục cũng là các tên phổ biến để xử lý nhiều mối quan hệ). Các bảng nối này thường là các bảng trung gian; tuy nhiên, các thuộc tính bổ sung có thể và thường được thêm vào chúng.

Ý định của lược đồ giả đã nêu là hơi âm u, nhưng tôi nghĩ những gì bạn dự định là các mục có thể yêu cầu nhiều kỹ năng; các vật phẩm cũng có thể yêu cầu các vật phẩm khác, mỗi vật phẩm có kỹ năng cần thiết của riêng chúng, có thể là vật phẩm cần thiết của riêng chúng, v.v., đến nhiều cấp độ sâu. Cảnh giác với các tham chiếu vòng tròn trong các mối quan hệ tự tham chiếu [nhiều-nhiều] của bạn, chẳng hạn như những gì có thể xảy ra trong 'containerItemMaps'. Lược đồ giả sau đây phản ánh cách tôi hình dung ý định của OP:

items (itemId PK, itemName, weight, volume, price)

skillMaps ( (itemId, skillId) PK)

skills (skillId PK, skillName)

containerItemMaps ( (containerItemId, componentItemId) PK)
    -- containerItemId is the parent/requiring item id
    -- componentItemId is the child/required item id

Thuật ngữ ActiveRecord đề xuất 'has_and_belongs_to_many' là kiểu kết hợp mối quan hệ trong mô hình dữ liệu để sử dụng trong tình huống này. Để biết thêm thông tin, bạn có thể muốn xem trang tại Hiệp hội datamapper.org . Cụ thể, các phần có tiêu đề 'Có và thuộc về nhiều người (hoặc Nhiều-Nhiều)' và 'Tự giới thiệu nhiều đến nhiều mối quan hệ'

Bởi vì tôi không phải là một anh chàng ruby ​​vào thời điểm này, tôi chỉ có thể nhầm lẫn với mã ruby ​​để đưa ra một ví dụ, nhưng đây là xấp xỉ tốt nhất của tôi về lớp vật phẩm của bạn sẽ như thế nào:

# revised
class Item
   include DataMapper::Resource

   property :id, Serial

   property :name, String, :required => true
   property :weight, Float
   property :volume, Float
   property :price, Float 

   has n, :componentMaps, :child_key => [:container_id]
   has n, :components, self, :through => :componentMaps, :via => :component

   has n, :skillMaps, :child_key => [:skill_id]
   has n, :skills, :through => :skillMaps, :via => :skill    
end

Và bảng bản đồ để tự tham khảo nhiều đến nhiều mục, ví dụ .. các mục bắt buộc:

#revised
class ComponentMap
  include DataMapper::Resource

  belongs_to :container, 'Item', :key => true
  belongs_to :component, 'Item', :key => true

  property :quantity, Integer, :default => 1
end

Để hoàn thiện:

class SkillMap
  include DataMapper::Resource

  belongs_to :item, 'Item', :key => true
  belongs_to :skill, 'Skill', :key => true

  property :mastery, Enum[:none, :aprentice, :journeyman, :craftsman, :master ], :default => :none

end

class Skill
    include DataMapper::Resource

    property :id, Serial
    property :name, String, :required => true

    has n, :skillMap, :child_key =>[:skill_id]     
end

Sửa đổi:

Nhận thấy mối quan tâm của bạn, tôi đã đi và cài đặt một trình thông dịch và trình gỡ lỗi để xác minh mã được biên dịch và sql phát ra là lý tưởng hơn. Ban đầu, tôi chỉ đi kiểm tra tài liệu. Các cấu trúc ở trên sẽ tạo ra sql có cấu trúc tốt từ các ánh xạ.

Bất kể bạn sử dụng trường và cấu trúc nào, và cho dù bạn chọn ORM nào (datamapper hoặc một số nhà cung cấp khác), bạn sẽ muốn chạy mã thông qua trình gỡ lỗi và chú ý đến sql mà nó phát ra vì đôi khi ánh xạ không nhất thiết những gì bạn có thể mong đợi đầu tiên.

Lưu ý thứ hai về các bảng nối (skillMap và thành phần Bản đồ): lưu ý tôi bao gồm các trường bổ sung (số lượng và thành thạo). Đây có vẻ là một sự phù hợp tự nhiên cho loại ứng dụng được mô tả ban đầu, mặc dù không được chỉ định ban đầu. Trong một công thức, một số thành phần phổ biến trong số nhiều kết hợp khác nhau, tuy nhiên số lượng từ công thức đến công thức khác nhau. Đối với các kỹ năng, như các thành phần, mức độ kỹ năng cần thiết để thực hiện các hoạt động nhất định khác nhau, và do đó tôi đã thêm một trường thành thạo vào bảng xếp hạng skillMap.

Tất nhiên, bạn có thể muốn thêm các quy tắc kinh doanh và chức năng trợ giúp phù hợp (để truy cập vào thành phần của các bộ sưu tập theo chương trình như thêm và xóa các phần tử, thêm và xóa các nhóm phần tử, v.v.).

Hy vọng rằng điều này chứng minh tốt hơn một chút lý do tại sao bạn có thể muốn xem xét và sử dụng bảng nối trên một hàm băm thẳng. Tất nhiên mỗi ứng dụng cụ thể là khác nhau và có lẽ khả năng chỉ định các khía cạnh bổ sung của mối quan hệ giữa vật phẩm và kỹ năng và vật phẩm và các vật phẩm khác là không cần thiết trong trường hợp của bạn.

Có và sử dụng kiểm soát bổ sung trong việc xác định các mối quan hệ rõ ràng có nhiều lợi thế so với việc dựa vào ánh xạ động / ma thuật. Trong một số trường hợp, tôi cảm thấy nó thực sự cần thiết, và tôi nghĩ trong trường hợp nhiều người, điều này đã được chứng minh. Đối với nhiều người, mối quan hệ dễ dàng được suy luận hơn và sử dụng phương pháp tạo ánh xạ linh hoạt hơn (ví dụ: có n ,: <nhóm thuộc tính> ,: thông qua => Tài nguyên) sẽ được chấp nhận.


Xin vui lòng xem chỉnh sửa của tôi ở trên. Xin lỗi vì tôi không thể diễn đạt nó bằng những từ ngắn hơn.
barerd

Cảm ơn rất nhiều. Trong 2 ngày, tôi đã so sánh một số tùy chọn cho một hàng tồn kho. Tôi thấy rằng bằng cách sử dụng has n, :items, :through => Inventoryphương pháp tiếp cận, tôi đã nhận được các truy vấn hiệu quả hơn so với cách tiếp cận giống như hàm băm. Bằng cách nào bạn đã sử dụng trình gỡ lỗi?
barerd

Đối với các phần sql: 'DataMapper :: Logger.new ($ stdout ,: debug)' Và về phía ruby, đá quý 'ruby-debug'; cả hai từ trong nhật thực
JustinC
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.