我有一個遺留數據庫,位於一個非常糟糕的PHP應用程序背後。 Web應用程序正在導致數據庫的各種問題,我只需要一種快速和骯髒的方式來表示存儲在數據庫中的內容,以便我的客戶可以看到問題的嚴重程度,所以我構建了一個Sinatra + DataMapper應用程序,但我在計算視圖中的某些值時遇到了麻煩。嵌套DataMapper資源的HTML表中計算rowspan
最後,我希望有一個表是這樣的:
+++++++++++++++++++++++++++++++++++++++++++++
+ Profile + Registration + Signup + Payment +
+ + + +++++++++++
+ + + + Payment +
+ + ++++++++++++++++++++
+ + + Signup + Payment +
+ +++++++++++++++++++++++++++++++++++
+ + Registration + Signup + Payment +
+ + ++++++++++++++++++++
+ + + Signup + + <- Signup w/ no payments
+++++++++++++++++++++++++++++++++++++++++++++
+ Profile + Registration + Signup + Payment +
+ +++++++++++++++++++++++++++++++++++
+ + Registration + + + <- Registration w/ no Signups
+++++++++++++++++++++++++++++++++++++++++++++
+ Profile + + + + <- Profile w/ no Registrations
+++++++++++++++++++++++++++++++++++++++++++++
我的第一個問題是,這需要一噸的SQL查詢[基本的(N + 1)*(N + 1)*(N +1)*(n + 1)],但AFAIK無法使DataMapper儘快加載嵌套模型,也無法以使讀取效率更高的方式來緩存數據模型。 (我沒有寫任何東西回數據庫,並且數據庫的快照很好 - 不關心實時更新)。目前這是可以忍受的,因爲這是一次性的報告。
我的第二個問題是計算給定列的rowspan。起初,我只是使用當前範圍的付款數量(profile.registrations.signups.payments.size
,registration.signups.payments.size
等),但正如您在上面的第一個示例中看到的那樣,實際上支付的支付少於準確的跨行個人資料。
我已經能夠想到的唯一理論解決方案是基本上循環遍歷每一個子對象,以確定哪些子對象在這一步之後可用,但是這看起來真的很不雅並且需要運行SQL的指數級增長。
有沒有其他方法可以解決這個問題?我沒有嫁給DataMapper或HAML,我只是想盡可能高效地完成這項工作。
我正在粘貼我現在的HAML和數據模型以供參考。
index.haml(這是討厭的,我知道)
#content
%p #{@profiles.size} Profiles
%table.display{:border=>1, :cellpadding=>2,:width=>'100%'}
%thead
%th Prof ID
%th Profile
%th Reg's
%th Reg ID
%th Registration
%th Signups
%th Event ID
%th Event
%th Event Date
%th Payments
%th Pmt ID
%th Amt
%th Pmt Date
%tbody
- @profiles.each do |profile|
- profile_rowspan = [profile.registrations.signups.payments.size, profile.registrations.signups.size, profile.registrations.size, 1].detect { |i| i > 0 }
%tr{:valign=>'top'}
%td{:rowspan => profile_rowspan, :class => "profile"} #{profile.id}
%td{:rowspan => profile_rowspan} #{profile.firstname} #{profile.lastname}
%td{:rowspan => profile_rowspan} #{profile.registrations.size}
- if profile.registrations.size == 0
%td{:rowspan => profile_rowspan}
%td{:rowspan => profile_rowspan}
%td{:rowspan => profile_rowspan}
%td{:rowspan => profile_rowspan}
%td{:rowspan => profile_rowspan}
%td{:rowspan => profile_rowspan}
%td{:rowspan => profile_rowspan}
%td{:rowspan => profile_rowspan}
%td{:rowspan => profile_rowspan}
%td{:rowspan => profile_rowspan}
- profile.registrations.each_with_index do |registration, reg_index|
- if reg_index != 0
!= "</tr><tr valign=\"top\">"
- reg_rowspan = [registration.signups.payments.size, registration.signups.size, 1].detect { |i| i > 0 }
%td{:rowspan => reg_rowspan, :class => "registration"} #{registration.id}
%td{:rowspan => reg_rowspan} #{registration.firstname} #{registration.lastname}
%td{:rowspan => reg_rowspan} #{registration.signups.size}
- if registration.signups.size == 0
%td{:rowspan => reg_rowspan}
%td{:rowspan => reg_rowspan}
%td{:rowspan => reg_rowspan}
%td{:rowspan => reg_rowspan}
%td{:rowspan => reg_rowspan}
%td{:rowspan => reg_rowspan}
%td{:rowspan => reg_rowspan}
- registration.signups.each_with_index do |signup, signup_index|
- if signup_index != 0
!= "</tr><tr valign=\"top\">"
- signup_rowspan = [signup.payments.size, 1].detect { |i| i > 0 }
%td{:rowspan => signup_rowspan, :class => "signup"} #{signup.event.id}
%td{:rowspan => signup_rowspan} #{signup.event.event_title}
%td{:rowspan => signup_rowspan} #{signup.event.event_start}
%td{:rowspan => signup_rowspan} #{signup.payments.size}
- if signup.payments.size == 0
%td{:rowspan => signup_rowspan}
%td{:rowspan => signup_rowspan}
%td{:rowspan => signup_rowspan}
- signup.payments.each_with_index do |payment, payment_index|
- if payment_index != 0
!= "</tr><tr valign=\"top\">"
%td{:class => "payment"} #{payment.id}
%td #{payment.total}
%td #{payment.payment_date}
profile.rb
class Profile
has n, :registrations
end
registration.rb
class Registration
belongs_to :profile
has n, :signups
has n, :payments
end
signup.rb
class Signup
belongs_to :registration
belongs_to :event
has n, :payments
end
payment.rb
class Payment
belongs_to :registration
belongs_to :signup
end
event.rb
class Event
has n, :signups
has n, :payments, :through => :signups
end