Welcome Guest, Not a member yet? Register   Sign In
[Deprecated] DMZ 1.5.3 (DataMapper OverZealous Edition)

[eluser]mcnux[/eluser]
Got another issue.

I've been doing a lot of partially building queries and then passing them around for the application to add to before executing. This has been seriously useful and I think is a major benefit of using query object. Unfortunately it appears to be breaking DataMapper. Take the following example:

Code:
$job = new Job();
$job->where_in('jobs.id',$idArray)->include_related('location','name');

$person = new Person();
$person->where_in('persons.id',$idArrayTwo)->include_related('address','post_code');

$job->get(); // This time I don't want to alter the query (keeping it simple)

// Results in something like:
SELECT
  jobs.*,
  location.name AS location_name,
  addresses.post_code as address_post_code // SECOND QUERY
FROM
  jobs
  LEFT OUTER JOIN locations ON jobs.location_id = locations.id
  LEFT OUTER JOIN addresses ON persons.address_id = addresses.id // SECOND QUERY
WHERE
  jobs.id IN(1,2,3)
  AND persons.id IN(1,2,3) // SECOND QUERY

So it looks like only a single query object instance is used for all models and therefore you have to build your query and execute it before building another?

(N.B. notice in sql above that persons table isn't included in the query - guessing because the query builder thinks we already have our primary table in jobs).

[eluser]mcnux[/eluser]
[quote author="OverZealous" date="1250886181"]@mcnux
I think this is caused by a bug fixed in the current (unreleased) version of DMZ. Try turning off $auto_populate_has_one, OR, rewrite your code to look like this (recommended for the time being):
[/quote]

I tried your suggestion but it hasn't worked? Where clause is still id IN(1,2,3) not jobs.id IN(1,2,3).

[eluser]ben_co[/eluser]
Hello,

I just started to use DMZ for the first time today and I wonder how I could do a save_all().

I'd like (for instance) to update the status of several documents in my documents table to draft|online ...

The problem is I'm forced to make a get() before updating data. Furthermore, I should create a loop for "all" results and apply save() on each record.

Executing all these queries seems really inefficient compared to a simple db->update() and I wonder if there is quicker/more efficient way to do that.

Any idea ? Maybe the answer is already in this topic but there're already 84 pages :lol: !!!

Thanks in advance !

[eluser]OverZealous[/eluser]
@mcnux
Yes, there is only one instance for queries. I can't change it, either, because it depends on CodeIgniter's Active record DBs.

If you need multiple query sets, there is a way that works, but it might give you performance issues. You basically do this for each object that needs it's own, unique copy, before using it:
Code:
$object->db = unserialize(serialize($object->db));

(I might have something typed in wrong, there, but you get the idea.)

Alternatively, back up every array that starts with 'ar_' on $object->db:
Code:
$object->query_backup = array();
foreach($object->db as $k => $v) {
    if(strpos('ar_', $k) === 0) {
        $object->query_backup[$k] = $v;
    }
}
Then simply map every item back onto $object:
Code:
foreach($object->query_backup as $k => $v) {
    $object->db->{$k} = $v;
}

[eluser]OverZealous[/eluser]
[quote author="mcnux" date="1250887838"]
I tried your suggestion but it hasn't worked? Where clause is still id IN(1,2,3) not jobs.id IN(1,2,3).[/quote]

Sorry, for this bug, you need to reverse the order of your query components:
Code:
$jobs->include_related('location','name')->where_in('id',$idArray)->get();

This forces DMZ to prepend the table name. I haven't decided yet if DMZ should always prepend the table name.

[eluser]OverZealous[/eluser]
[quote author="ben_co" date="1250888097"]Executing all these queries seems really inefficient compared to a simple db->update() and I wonder if there is quicker/more efficient way to do that.[/quote]

DMZ does not provide support for bulk updates. It is primarily focused on making changes to single objects. However, you can still call the normal, built-in ActiveRecord functions.

If you want, this could be written as an extension, to prevent duplicating a lot of code. Something like this:
Code:
function bulk_update($object, $params) {
    // $params would be an associative array of key/value pairs
    return $object->db->update($object->table, $params);
}

Usage:
Code:
$obj->load_extension('bulk_update');
$result = $obj->where('id >' 4)->bulk_update(array('foo' => 'bar'));

If you are creative, you might be able to expand this to be more useful.

[eluser]ben_co[/eluser]
Thanks for this quick answer !

What a pity isn't not included yet Smile ... I mean, bulk update could also concern related objects for instance... what becomes more interesting and useful in my opinion.

Ok, I'll take the time to write an extension (and of course share it Wink ).

[eluser]mcnux[/eluser]
[quote author="OverZealous" date="1250888291"]
Sorry, for this bug, you need to reverse the order of your query components:
Code:
$jobs->include_related('location','name')->where_in('id',$idArray)->get();

This forces DMZ to prepend the table name. I haven't decided yet if DMZ should always prepend the table name.[/quote]

That's cracked it. That order makes more sense anyway I guess so I'll just remember to construct as I would the query.

[eluser]mcnux[/eluser]
[quote author="OverZealous" date="1250888178"]
Yes, there is only one instance for queries. I can't change it, either, because it depends on CodeIgniter's Active record DBs.[/quote]
Okay thanks.

[eluser]ben_co[/eluser]
[quote author="OverZealous" date="1250888593"]
Code:
$obj->load_extension('bulk_update');
$result = $obj->where('id >' 4)->bulk_update(array('foo' => 'bar'));
[/quote]

Ok for the usage, there isn't more simpler way.

After further thoughts however... I realized it's a bit semantically incorrect to do in this way...

Maybe I'm too strict about that but it's a bit nonsense - let's say in my point of view - to create a new datamapper model instance and then calling a method on an empty object as model should be more considered as definition or factories, not "record containers"... a bit like the default ci models declaration finally:

Code:
$this->datamapper->load_extension('bulk');
$this->datamapper->load('datamodel');
$this->datamodel->where('id >', 4);
$this->datamodel->update((array('foo' => 'bar'));

But to achieve doing that, we should also modify the main Datamapper code and add some more methods on the CI Loader class (it should be not really difficult by the way).

Along these lines, get some records could be coded like this:

Code:
$this->datamapper->load('datamodel');
$this->datamodel->where('id =', 4);
$record = $this->datamodel->get(); // $record contains new datas
$record->{field}='newvalue';
$record->save(); // update

Code:
$this->datamapper->load('datamodel');
$this->datamodel->where('name !=', 'Bill');
$records = $this->datamodel->get(); // $records is an array containing new datamodel records
foreach ($records as $record)
{
...
}

Code:
$this->datamapper->load('datamodel');
$record = $this->datamodel->new_record(); // more like in the ignited record way
$record->{field}='newvalue';
$record->save(); // insert

Code:
$this->datamapper->load('datamodel');
$record = $this->datamodel->get_by('id >', 4); // $record contains new datas
$record->{field}='newvalue';
$record->destroy(); // record deleted and resets to a new empty record

Code:
$this->datamapper->load('datamodel');
$this->datamodel->where('id >', 4);
$this->datamodel->delete(); // delete records that satisfy the where condition

OK... Notice that the goal of this comment wasn't of course to criticize your excellent work and contribution ;-)... but I feel it would be more correct to do in this way - I know, maybe it's a bit strange...

What do you think about this way to code ? Don't hesitate to be honest ... If you think it's a really stupid way, just say it... I'm trying to improve myself ;-).




Theme © iAndrew 2016 - Forum software by © MyBB