У меня есть устаревшая база данных, которая находится за действительно дрянным приложением PHP.Веб-приложение вызывает все виды проблем с базой данных, и мне просто нужен быстрый и грязный способ представления того, что хранится в базе данных, таким образом, чтобы мой клиент мог видеть, насколько серьезна проблема, поэтому я создалПриложение Sinatra + DataMapper, но у меня возникают проблемы с вычислением некоторых значений в представлении.
В конце я хочу следующую таблицу:
+++++++++++++++++++++++++++++++++++++++++++++
+ 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 быстро загружать вложенные модели, ниво всяком случае, кэшировать модель данных таким образом, чтобы сделать чтение более эффективным.(Я ничего не записываю обратно в БД, и снимок базы данных в порядке - на самом деле нет дела до живых обновлений).На данный момент это допустимо, потому что это однократный отчет.
Моя вторая проблема - вычисление диапазона строк для заданных столбцов.Сначала я просто использовал количество платежей для текущей области (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
событие.руб
class Event
has n, :signups
has n, :payments, :through => :signups
end