ExpressionEngine CMS
Open, Free, Amazing

Thread

This is an archived forum and the content is probably no longer relevant, but is provided here for posterity.

The active forums are here.

DMZ 1.7.1 (DataMapper OverZealous Edition)

March 14, 2010 11:43pm

Subscribe [104]
  • #406 / Jul 07, 2010 1:26am

    TheJim

    35 posts

    squawk, when you access a related model from your object and call get(), you’re accessing only those records related to your current object.  That is $b->user->get() is not going to be all User records, but only those related to whatever Buyer is stored in $b (after a call to get(), this would be the first Buyer record loaded).  So that’s why the WHERE clause exists in those generated queries.  Your sentence “the relationship fields are also not filled for this record [your first result: Buyer 353]” explains why nothing was loaded after your calls to get() for the related objects.

    It sounds like you might need to read through the manual more thoroughly to make sure you’re clear on relationships.  And if you’re wanting those relationships included for each Buyer object, I’d especially look at the include_related function for efficiency’s sake.

  • #407 / Jul 07, 2010 3:05am

    anaxamaxan

    16 posts

    To add to what TheJim has already accurately pointed out, your code could be explained like this:

    $b = new Buyer();
    $b->order_by('updated', 'desc')->get($limit, $offset);
    $b->user->get(); //gets the user for only the first record returned by the get() above
    $b->place->get(); // gets the the place for only the first record,
    $b->objtype->get();  // etc

    Using a simple include_related will likely do the trick in this case, e.g.:

    $b = new Buyer();
    $b->order_by('updated', 'desc')
      ->include_related('user',null,true,true)
      ->include_related('place',null,true,true)
      ->include_related('objtype',null,true,true)
      ->get($limit, $offset);

    See also the docs section about auto-populating related objects, Setting Up Relationships in the DMZ docs.

  • #408 / Jul 07, 2010 7:14am

    sqwk

    83 posts

    So if some of the relationships are has-many relationships, I would have to use get_iterated(), loop over the result set and add the related object like I did before?

  • #409 / Jul 07, 2010 11:47am

    TheJim

    35 posts

    Yes, include_related won’t pull in has_many relationships.  However, there are other ways to consider setting it up if looping over your main result and querying related objects slows you down with more queries than you’d like.  It depends on on your circumstances, but you could go the other direction: run the query on your has_many object and use include_related for your main has_one.  Or you could run separate queries and from the has_many side, include only your has_one’s ID to relate to an already-loaded record.  It really all depends on your data and how many queries will be involved in loading a typical page.

    So, the short answer is yes, but consider alternatives if necessary.

  • #410 / Jul 07, 2010 12:09pm

    sqwk

    83 posts

    Both objtype and place are has-many relationships and I allow up to three relationships per one buyer. A single page can display up to 100 records, so looping over the object would give me an additional 600 queries, which is why I am slightly hesitant to use it.

    I was thinking about condensing all the ids from the buyer query into a comma separated list, to then only load all the places/objtypes that I need with one query. (Where_in) To join them I would need to loop over the buyer object a second time. This gives me less queries, but more logic. Whether this is the fastest option I do not know…

  • #411 / Jul 07, 2010 12:44pm

    TheJim

    35 posts

    I would say for your circumstances, what you’re thinking is probably the right way to go about it.  I’d maybe test it against the simple looping and querying method since it’s easy to code, but with that many additional queries, I think you’re almost guaranteed to be much faster with the extra logic.

  • #412 / Jul 07, 2010 1:12pm

    anaxamaxan

    16 posts

    Oh, duh. Hey thanks TheJim.  In spite of the red “warning” box in the docs, I never even noticed that include_related doesn’t work with has_many relations—I guess I’ve only used it with has_one since that’s when it’s most useful.  Sorry about the noise.

  • #413 / Jul 07, 2010 8:48pm

    OverZealous

    1030 posts

    @anaxaman,TheJim,squawk

    One of the things I am planning for the next version of DMZ is to remove the has_one restriction on include_related.  The original reason for this restraint had to do with how objects were stored in the all array, but for a while now, DMZ would work fine with multiple results per id.

    Of course, it won’t do exactly what might be expected (unless I write a lot more logic in), since you’ll get one row per unique result, even if that means multiple rows per id.

    (I might add some logic in to optionally loop through the results and consolidate the rows when instantiating related items.)

    But don’t wait around on the next version…  It might be until Fall before I can get to working on DMZ again.

  • #414 / Jul 08, 2010 6:58pm

    sqwk

    83 posts

    More difficult that I thought;-) How can I get the just the places that are related to the buyers that I already have in one object? I found where_in_related, but I am not entirely sure on how to use it. And what logic would I need to loop through the buyers and add the relevant places? The problem that the actual linking info is in the join table so not in either two objects… Any ideas?

  • #415 / Jul 08, 2010 7:13pm

    TheJim

    35 posts

    Something like:

    // Load records into $buyers however you want
    ...
    
    $ids = array();
    foreach ($buyers as $b)
         $ids[] = $b->id;
    
    $place = new Place();
    $place->where_in_related('buyer', 'id', $ids)->get();
    
    ...

    That may not have whatever nuances you might need for your situation, but I think it should get you pointed in the right direction.

  • #416 / Jul 08, 2010 7:26pm

    sqwk

    83 posts

    Actually I whipped up this in the meantime:

    foreach ($b as $row)
        $buyer_ids[] = $row->id;
    $buyer_ids = implode(',', $buyer_ids);
    
    $p = new Place();
    $p->where_in_join_field('buyer', 'buyer_id', $buyer_ids);
    $p->include_join_fields();
    $p->get_iterated();
    
    foreach ($b as $buyer)
        foreach ($p as $place)
        if ($buyer->id == $place->buyer_id)
                $buyer->place[] = $place;

    This generates the following query:

    SELECT * FROM (`places`) WHERE `buyers_places`.`buyer_id` IN ('353,348,347,346,345,…')

    What would I need to JOIN the join table?

  • #417 / Jul 08, 2010 7:28pm

    TheJim

    35 posts

    Oh, and you wanted to link them:

    $place->where_in_related('buyer', 'id', $ids)->include_related('buyer', 'id')->get(); // or get_iterated if suitable
    foreach ($place as $p)
    {
        $b = $buyers->all[$p->buyer_id];
        ...
    }

    That would be one way to link if your configuration is set up to index the $all array by ID.  That has consequences with getting multiple records in queries, so you might want to just make a simple reference map yourself when you’re getting the IDs (or only doing the map and using array_keys, or whatever):

    $ids = array();
    $map = array();
    foreach ($buyers as $b)
    {
         $ids[] = $b->id;
         $map[$b->id] =& $b;
    }

    If there are any errors in my example code, sorry, but it should at least provide guidance.

  • #418 / Jul 08, 2010 7:33pm

    TheJim

    35 posts

    It looks like you’re manually joining them, but where_in_related would do that for you.  To answer your question, you shouldn’t have to add anything to the join table, you just have to include the Buyer ID in your query.

    Also, your code

    foreach ($b as $buyer)
        foreach ($p as $place)
            $buyer->place[] = $place;

    will just give you all places for all buyers, not what you want.

  • #419 / Jul 08, 2010 7:38pm

    sqwk

    83 posts

    Yes, I just saw that as well—edited the foreach and threw in an if.

    Include_related won’t work as it is a has_many relationship.

  • #420 / Jul 08, 2010 7:48pm

    TheJim

    35 posts

    I see.  I was thinking it was one-to-many for buyers to places, for whatever reason.

    I’d probably still use where_in_related over where_in_join_field though.  To me it adds clarity to the code, though you’re of course welcome to do whatever you prefer.

.(JavaScript must be enabled to view this email address)

ExpressionEngine News!

#eecms, #events, #releases