CodeIgniter Forums
DataMapper ORM v1.8.0 - Printable Version

+- CodeIgniter Forums (https://forum.codeigniter.com)
+-- Forum: Archived Discussions (https://forum.codeigniter.com/forumdisplay.php?fid=20)
+--- Forum: Archived Libraries & Helpers (https://forum.codeigniter.com/forumdisplay.php?fid=22)
+--- Thread: DataMapper ORM v1.8.0 (/showthread.php?tid=37531)



DataMapper ORM v1.8.0 - El Forum - 05-26-2011

[eluser]WanWizard[/eluser]
It's difficult to comment on your database design without knowing the requirements.
But I don't understand the relation between donation and bloodtype, donations don't have blood types, donors do (you can get the donor's blood type using include_related).

As to your queries, you have to ask yourself if you need the information as a flat table (in which case you use include_related) or as objects (slower, but allows you to update the results).
The iterated versions of get() are faster then the standard get(), and uses a lot less memory. But is restricted in it's use, you can only itterate over the result (using a foreach), no direct access is possible.

This query will give redundant information, you'll get a record for every donation, which all donator fields and the count repeated.

Try to avoid subqueries if possible, in a lot of cases they are not needed (I think in this cause a simple countand a group_by would give you the same result). And if you need the individual donations,you can use the result count (in case of a get) or count the results when you loop through them.


DataMapper ORM v1.8.0 - El Forum - 05-26-2011

[eluser]Arministrator[/eluser]
[quote author="WanWizard" date="1306422782"]
But I don't understand the relation between donation and bloodtype, donations don't have blood types, donors do (you can get the donor's blood type using include_related).
[/quote]

I need to be able to access just donations, without donors. And a donation can be of bloodype A, B, etc, so I guess it has many bloodtypes.

E.g. I want to retrieve all donations for past month for bloodtype A.

[quote author="WanWizard" date="1306422782"]
As to your queries, you have to ask yourself if you need the information as a flat table (in which case you use include_related) or as objects (slower, but allows you to update the results). [/quote]

Donations will always just be a list, without the need to be changed. Only donors will have attributes that can change.

[quote author="WanWizard" date="1306422782"]
This query will give redundant information, you'll get a record for every donation, which all donator fields and the count repeated.[/quote]

This is true, print_r shows loads of repeated and unnecessary stuff.

[quote author="WanWizard" date="1306422782"]
Try to avoid subqueries if possible, in a lot of cases they are not needed (I think in this cause a simple countand a group_by would give you the same result). And if you need the individual donations,you can use the result count (in case of a get) or count the results when you loop through them.[/quote]

Ok, this is the new version:

Code:
$donator = new Donator();
$donator->where('email', $this->input->post('email'))->get();
$donator->bloodtype->get();
$donator->donation->get_iterated();

I get the donation dates with a foreach loop, as a list.

This is much cleaner, but still plenty redundant data. Any suggestions?


DataMapper ORM v1.8.0 - El Forum - 05-26-2011

[eluser]WanWizard[/eluser]
[quote author="Arministrator" date="1306423505"]I need to be able to access just donations, without donors. And a donation can be of bloodype A, B, etc, so I guess it has many bloodtypes.[/quote]
Still, from a database design perspective, a donation doesn't have a bloodtype.

If you need to know all donations for blood type B+, you need to query all donations done by donors with that bloodtype. Now you have to do double administration, which the chance of errors if you're not careful (you can easily relate a donor with O with a donation with B+).

If you want to list donations, run the query from the donations object:
Code:
$donations = new Donation();
$donations->include_related('bloodtype')->where_related_donator('email', $this->input->post('email'))->get_iterated();
You can limit the fields in the result with a select() or by listing fields to include on the include_related(), if needed.

If you dump the objects, you might see redundant data not related to the database record. No worries, those are references, they don't take up any space (except for the reference of course).


DataMapper ORM v1.8.0 - El Forum - 05-26-2011

[eluser]treeface[/eluser]
First off...WanWizard, thanks a lot for the work you've put into this! I appreciate it immensely. I created an issue on bitbucket about this problem I'm having, but after posting it anonymously, I immediately realized that I probably should've just come to this forum instead. Now I can't get rid of it :-). Sorry about that.

At the moment I'm having a small problem with aliased relations. At the moment, I have a users table that has all the standard user information, including an id, and a form_data table that has its own id and a field called created_by which links to the id column on the users table. To put it more simply, users-form_data is a one-to-many relationship. My DataMapper models look like this:

Code:
class user extends DataMapper {

    var $has_many = array(
        'form_data_created_by' => array(
            'class' => 'form_data',
            'other_field' => 'created_by'
        )
    );
}

...and more, of course, but edited here for brevity

And my form_data model looks like this:

Code:
class form_data extends DataMapper {
    var $table = 'form_data';

    var $has_one = array(
        'form_type',
        'created_by' => array(
            'class' => 'user',
            'other_field' => 'form_data_created_by'
        )
    );
}

Now here's the thing. When I run this code:

Code:
$form_type = new form_type();
$form_data = $form_type->where('app_id', $app_id)->get()->form_data->get()->all_to_array();

It throws an error that is something like this:

Code:
Severity: Warning
Message:  Invalid argument supplied for foreach()
Filename: datamapper/array.php
Line Number: 53

And when I echo out the JSON of the $form_data object, I get this:

Code:
{"id":1,"form_type_id":"3","create_date":"1306241597","created_by":[],"status":"a"}

Notice how created_by is an empty array? The column in my table is definitely called created_by. The odd thing is that when I change this column to user_id and change the form_data class to have this:

Code:
var $has_one = array('form_type', 'user');

...and change the user class to have this:

Code:
var $has_many = array('form_data') //among others

Everything works perfectly, and I get the right value for user_id with JSON that looks something like this:

Code:
{"id":1,"form_type_id":"3","create_date":"1306241597","user_id":"1","status":"a"}

I'm 99% sure I'm doing something wrong, but after staring at the docs and the examples for hours, I can't seem to figure it out.

Thanks!


DataMapper ORM v1.8.0 - El Forum - 05-27-2011

[eluser]Arministrator[/eluser]
I guess you're right about donations. If i got it right, they should be related to donors, but have no relation to bloodtype? Makes sense.

So:

donators (I know it's miss-spelled, but I need to use 'donor' for something else)
bloodtypes
donations
bloodtypes_donators
donations_donators

So what would be the best way to query a donor with all his donations?

This is what I came up with, but there's still a lot of redundancies. E.g. email value is returned 24 times. (dump) Could this code be any better? I'm trying not just to get it working, but to understand it, and optimize the process as much as possible.

Code:
$donator = new Donator;
$donator->where('email', $this->input->post('email'))->include_related('bloodtype')->get();
$donator->donation->get_iterated();

Resulting query:
Code:
SELECT `donations`.* FROM (`donations`) LEFT OUTER JOIN `donations_donators` donations_donators ON `donations`.`id` = `donations_donators`.`donation_id` WHERE `donations_donators`.`donator_id` = 70

I hope I'm not becoming annoying, but I probably will have a couple of more questions. I'm not trying to get you guys to do my work, but I've never used object approach on a database, and want to get it right the first time. Smile

A big thank you, wanwizard.


DataMapper ORM v1.8.0 - El Forum - 05-27-2011

[eluser]WanWizard[/eluser]
The only thing you can do is not to flatten the result, but that will mean two queries. You have to make the decision on memory usage vs cpu and I/O usage.

Code:
$donator = new Donator;
$donator->get_by_email($this->input->post('email'));
$donator->donation->get_iterated();

// now $donator contains your donor information. you can include bloodtype if you want
// and you can foreach() over $donator->donation to list all donations of this donor.



DataMapper ORM v1.8.0 - El Forum - 05-27-2011

[eluser]WanWizard[/eluser]
@treeface,

In your model definition 'created_by' is a related model, so your column value in the object will be overwritten by Datamapper to add the relation (i.e. $form_type->created_by points to a user object, and no longer to a column).


DataMapper ORM v1.8.0 - El Forum - 05-27-2011

[eluser]treeface[/eluser]
[quote author="WanWizard" date="1306511551"]@treeface,

In your model definition 'created_by' is a related model, so your column value in the object will be overwritten by Datamapper to add the relation (i.e. $form_type->created_by points to a user object, and no longer to a column).[/quote]

Thanks for taking the time to answer! I'm still a bit confused though. Is it possible that the output has a field that looks like this:

Code:
"created_by":"1"

It does this when I don't give the column a special name (i.e. user_id). Sorry for the confusion..


DataMapper ORM v1.8.0 - El Forum - 05-27-2011

[eluser]treeface[/eluser]
Incidentally, when I run the exact same code with all_to_json() it works perfectly. Could this be a bug in the all_to_array() method?


DataMapper ORM v1.8.0 - El Forum - 05-28-2011

[eluser]WanWizard[/eluser]
Difference is that the array methods support relations, which means they embed the related object into the array output, where as the json methods only dump the current object. In that respect you could say the json methods need updating.

Problem still is that you only have one $object->created_by, and it can either point to a table column, or to a related object, but not both. So rename your relation or your column name to avoid this issue.