Thanks goes to stensi, for providing such an amazing code base to work on.
DataMapper OverZealous Edition 1.5.3
DataMapper (DM) is an Object-Relational Mapper that builds on ActiveRecord. Data is loaded from database tables into objects, and relationships can be managed through simple, easy-to-read functions.
DataMapper OverZealous Edition (DMZ) adds several important features to DM, enhancing it’s usage, usually without requiring any code changes.
To install DMZ over DataMapper, the (fairly simple) upgrade process is described here.
DMZ offers these features and more over the original DataMapper:
• In-table foreign keys
• Multiple relationships to the same model
• Better self references
• Add fields from a related model into one query
• Update, view, and query extra columns on join tables
• A shareable extension mechanism, including:
• Easy creation of HTML forms,
• Processing posted input,
• Converting to-and-from JSON, CSV, and arrays, and
• Query caching
Version 1.5.3:
Recommended for a few minor bugfixes, and one semi-major one with include_related.
Core Changes
• Modified the way _to_object and query processing works, significantly, by merging all query processing code into one new function (_process_query).
Bug Fixes
• Fixed bug that completely broke include_required’s ability to automatically add all fields.
• Fixed bugs with get_rules not being called correctly for related queries and validate->get() queries.
• Invalid relationship queries now show an error instead of silently failing.
• Fixed typo in Troubleshooting where the word ‘related’ was supposed to be ‘required’.
I have decided to repost my question here cause Im pretty sure the answer to what Im looking for has to do with dmz more than datamapper
Could you help me with this query please??...
Heres my structure:
clients have many events
event has one client
events have one receipt
receipt has one event
receipts have many payments
payments have many receipts
I want to get every payment of a client in a single query… is it possible?
lets assume client id=1… I have tried many queries but I can never seem to get it done.
@NachoF
Short answer, no. I recommend that you relate Clients directly to Payments, and keep track of them that way. It looks like, from the names, these are written to but not updated. Since every Payment has a single Client, just add client_id to your Payments table, and add the Client whenever you INSERT a payment.
Longer answer:
Yes, you can, but you have to basically write your query by hand. And you’ll probably end up with weird duplications, due to the many-to-many between Receipts and Payments.
How I have done that, before I wrote DMZ, is to use this trick:
// note: adding the joins directly to the DB class $payments->db->join('payments_receipts', 'payments.id = payment_receipts.payment_id'); $payments->db->join('receipts', 'receipts.id = payment_receipts.receipt_id'); $payments->db->join('events', 'receipts.event_id = events.id'); $payments->where('events.client_id', $client->id); $payments->distinct()->get();
However, I highly recommend against this. It becomes hard to maintain and it’s awkward to read. Storing the client_id on Payments will also be an order of magnitude (or two) faster to query.
Also, I’m curious why payments are many-to-many to receipts? There can be more than one receipt per payment?
Finally, you should go back and edit (delete with a note) your comment on the DM 1.6.0 board, to avoid cross-posting.
@NachoF
Short answer, no. I recommend that you relate Clients directly to Payments, and keep track of them that way. It looks like, from the names, these are written to but not updated. Since every Payment has a single Client, just add client_id to your Payments table, and add the Client whenever you INSERT a payment.
Longer answer:
Yes, you can, but you have to basically write your query by hand. And you’ll probably end up with weird duplications, due to the many-to-many between Receipts and Payments.
How I have done that, before I wrote DMZ, is to use this trick:
// note: adding the joins directly to the DB class $payments->db->join('payments_receipts', 'payments.id = payment_receipts.payment_id'); $payments->db->join('receipts', 'receipts.id = payment_receipts.receipt_id'); $payments->db->join('events', 'receipts.event_id = events.id'); $payments->where('events.client_id', $client->id); $payments->distinct()->get();
However, I highly recommend against this. It becomes hard to maintain and it’s awkward to read. Storing the client_id on Payments will also be an order of magnitude (or two) faster to query.
Also, I’m curious why payments are many-to-many to receipts? There can be more than one receipt per payment?
Finally, you should go back and edit (delete with a note) your comment on the DM 1.6.0 board, to avoid cross-posting.
Ok, dont worry…. my entity relation cannot be modified… my teacher is crazy…the reasoning behind the many to many relation is that suppose a client has two pending events to be charged for… I have to give him the option to with just one payment pay those two receipts…. see?... you can pay for the event in different payments but in the end only get one receipt per event…. yet with one payment you can pay for more than one event.
Anyway, my query has been done in steps…
first get all the events of the client
then loop through them and get the receipts for each event and for each receipt loop and get the payments… its confusing but it seems to work so far….
One thing I forgot to mention that might save you a query is to use where_related() to reduce the number of queries.
Example (assumes Events has a client_id field):
// get all receipts for the customer $receipts = new Receipt(); $receipts->where_related_event('client_id', $client->id)->select('id')->get(); $receipt_ids = new array(); foreach($receipts->all as $r) { $receipt_ids[] = $r->id; } // get all payments that belong to one of the receipts $payments = new Payment(); $payments->where_in_related_receipt('id', $receipt_ids)->distinct()->get();
This should get all of the payments, distinctly, that are related to the client, in just 2 queries.
The nice thing about this is that you can still sort the payments list all at once.
Let me know if the above code works, since I typed it off the top of my head.
@NachoF join_related:
Join fields from a related class. In other words, I can include the name field of the model Group while querying my Users. This allows you to get information from related models all in one query. It’s really useful when querying data for a table, because you avoid running many queries to pull in all the data.
Join related includes the specified fields as <related_field>_<column_name>. You specify which related model in the first parameter, and which columns using the second parameter.
include_join_fields:
This allows you to include fields that are stored on a join table. In this case, you might want to track how many times a specific user has viewed a specific post, or something similar. You related the user like normal, but you can include extra columns on the join table that you can query, view, and update using where_join_field, include_join_fields, and set_join_field respectively.
I had already create join_related when I added the join table methods, so the names are a little confusing. I didn’t want to rename it, because it would break code (or require rewrites).
If I did rename it, I might rename it include_related_fields to make it consistent with the other one. (I might even make the second parameter optional, although that is not very efficient.)