Monday, March 5, 2012

Re: Saving simple associations

Jeremy thank you for your detailed reply.

> Your field on the people table should be country_id, not countries_id. It's always the singular table name plus '_id' (i.e. country_id) not the name of the table, which is always plural (i.e. countries_id).

I had renamed the countries_id -> country_id already before my last
email due to advice on the CakePHP mIRC channel. However, this does
not solve the problem.

> Then your data array becomes:
>
> $people = array
> (
>         'Person' => array(
>                 0 => array(
>                         'age' => 23,
>                         'country_id' => 1 // assuming the id of Belgium = 1
>...

This example is exactly what I wish to avoid. When I add new people, I
know their country names and these country names might or might not be
saved in the database. I know how to check when this names already
exist and when they do, how to get their ids. However, I thought that
the purpose of saveAll() method (which is basically a wrapper around
saveAssociated()) is to avoid of this (for me annoying) work. I
thought that I can save new people without _manually_ checking for
counties' ids. So my question now is: is what I wish to do even
possible in Cake? Today I also upgraded to 2.1.0 version and enabled
the 'deep' option as follows:

$this->Person->saveAssociated($data, array('deep' => true');

> Note that you haven't had to create the Person.id field values - Cake will always take care of that for you.
Oh, this was my mistake, I wanted to re-save people with ids that
already existed when I rerun the code. The program should throw an
error here, but obviously my code does not even try to save new people
if country names already exist in the database. Anyway, for my future
test, I removed the 'id's from $people.

Thanks!

On Mar 5, 12:04 pm, Jeremy Burns | Class Outfit
<jeremybu...@classoutfit.com> wrote:
> There are some non standard aspects to your code that might contribute to your problem. My advice would be to make some small changes and stick to conventions, if that's possible.
>
> Your field on the people table should be country_id, not countries_id. It's always the singular table name plus '_id' (i.e. country_id) not the name of the table, which is always plural (i.e. countries_id).
>
> Then your data array becomes:
>
> $people = array
> (
>         'Person' => array(
>                 0 => array(
>                         'age' => 23,
>                         'country_id' => 1 // assuming the id of Belgium = 1
>                 ),
>                 1 => array(
>                         'age' => 12,
>                         'country_id' => 2 // assuming the id of Austria = 2
>                 ),
>                 2 => array(
>                         'age' => 55,
>                         'country_id' => 1
>                 )
>         )
> );
>
> ...and your save command is:
>
> $this->Person->saveAll($people['Person']);
>
> Note that you haven't had to create the Person.id field values - Cake will always take care of that for you.
>
> If you want to collect the country_id value as well, do this:
>
> $countries = $this->Country->find(
>         'list',
>         array(
>                 'conditions' => array(
>                         'Country.name' => array(
>                                 'Austria', 'Belgium'
>                         ),
>                         'fields' => array(
>                                 'Country.name', 'Country.id'
>                         )
>                 )
>         )
> );
>
> This will return you an array of countries similar to this:
>
> Array
> (
>     ['Austria'] => 1
>     ['Belgium'] => 2
> )
>
> So you could modify the $people array to:
>
> $people = array
> (
>         'Person' => array(
>                 0 => array(
>                         'age' => 23,
>                         'country_id' => $countries['Belgium']
>                 ),
>                 1 => array(
>                         'age' => 12,
>                         'country_id' => $countries['Austria']
>                 ),
>                 2 => array(
>                         'age' => 55,
>                         'country_id' => $countries['Belgium']
>                 )
>         )
> );
>
> ...and it will insert the correct country_id for you.
>
> Jeremy Burns
> Class Outfit
>
> http://www.classoutfit.com
>
> On 5 Mar 2012, at 10:21, FirstTimeBaker wrote:
>
>
>
>
>
>
>
> > Jeremy thanks, but the problem remains.
>
> > When I rerun the code, SQL log looks like this:
> > SELECT COUNT(*) AS `count` FROM `countries` AS `Country` WHERE
> > `Country`.`name` = 'Belgium'
> > SELECT COUNT(*) AS `count` FROM `countries` AS `Country` WHERE
> > `Country`.`name` = 'Austria'
> > SELECT COUNT(*) AS `count` FROM `countries` AS `Country` WHERE
> > `Country`.`name` = 'Belgium'
>
> > So Cake just looks if countries already exist and it does not perform
> > any insert.
>
> > Could it be possible that I _must_ manually  set the persons.person_id
> > when I insert people? However, it puzzles me that the code works when
> > a new person's country does not exist in the table, and not
> > otherwise.
>
> > Also, is there a better place to ask this kind of question?
>
> > Thanks.
>
> > On Mar 5, 8:10 am, Jeremy Burns | Class Outfit
> > <jeremybu...@classoutfit.com> wrote:
> >> Try adding $this->Person->create(); before $this->Person->saveAll($data);
>
> >> Jeremy Burns
> >> Class Outfit
>
> >>http://www.classoutfit.com
>
> >> On 4 Mar 2012, at 12:15:03, FirstTimeBaker wrote:
>
> >>> Tilen hvala but that's not it. the problem is that if a country
> >>> already exists in the table, the code does not insert anything. So if
> >>> I rerun the code above, not a single person is added.
>
> >>> On Mar 3, 11:43 pm, Tilen Majerle <tilen.maje...@gmail.com> wrote:
> >>>> In ur for statement use $i++ instead of ++$i :)
>
> >>>> Dne sobota, 03. marec 2012 je poĊĦiljatelj FirstTimeBaker <
> >>>> thinkgrea...@gmail.com> napisal:
>
> >>>>> Hi all.
>
> >>>>> I am new with CakePHP and I have the following problem with testing
> >>>>> associations.
>
> >>>>> I have two objects: a country and a person. One person can live in one
> >>>>> country and a country can have many people. I have two test tables as
> >>>>> follows:
>
> >>>>> Table countries:
>
> >>>>> CREATE TABLE IF NOT EXISTS `countries` (
> >>>>>  `id` int(11) NOT NULL AUTO_INCREMENT,
> >>>>>  `name` varchar(20) NOT NULL,
> >>>>>  PRIMARY KEY (`id`),
> >>>>>  UNIQUE KEY `a` (`name`)
> >>>>> ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
>
> >>>>> Note, that the field name in countries has to be unique.
>
> >>>>> Table people:
>
> >>>>> CCREATE TABLE IF NOT EXISTS `people` (
> >>>>>  `id` int(11) NOT NULL AUTO_INCREMENT,
> >>>>>  `age` int(11) NOT NULL,
> >>>>>  `countries_id` int(11) NOT NULL,
> >>>>>  PRIMARY KEY (`id`,`countries_id`),
> >>>>>  UNIQUE KEY `name_UNIQUE` (`age`),
> >>>>>  KEY `fk_persons_countries` (`countries_id`)
> >>>>> ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
>
> >>>>> As you can notice, both tables are associated through the foreign key
> >>>>> 'countries_id' in people.
>
> >>>>> I have the corresponding models:
>
> >>>>> Model Country:
>
> >>>>> <?php
> >>>>>        class Country extends AppModel {
> >>>>>                public $name = 'Country';
>
> >>>>>                var $useDbConfig = 'test'; // We use the test database.
>
> >>>>>                public $validate = array ('name' => 'isUnique');
>
> >>>>>                public $hasMany = array(
> >>>>>                        'Person' => array(
> >>>>>                                'className' => 'Person',
> >>>>>                                'foreignKey'    => 'countries_id'
> >>>>>                        ));
> >>>>>        }
> >>>>> ?>
>
> >>>>> Model Person:
>
> >>>>> <?php
> >>>>>        class Person extends AppModel {
> >>>>>                public $name = 'Person';
>
> >>>>>                var $useDbConfig = 'test'; // We use the test database.
>
> >>>>>                public $belongsTo = array('Country'  => array(
> >>>>>                                        'className'    => 'Country',
> >>>>>                                        'foreignKey'   => 'countries_id'
> >>>>>                        ),);
> >>>>>        }
> >>>>> ?>
>
> >>>>> In people controller I wish to add the following three people:
>
> >>>>> $people = array
> >>>>> (
> >>>>>    array('id' => 1, 'age' => 23, 'country' => 'Belgium'),
> >>>>>    array('id' => 2, 'age' => 12, 'country' => 'Austria'),
> >>>>>    array('id' => 3, 'age' => 55, 'country' => 'Belgium')
> >>>>> );
>
> >>>>> with the following code:
> >>>>> for ($i = 0; $i < 3; ++$i)
> >>>>> {
> >>>>>   $data['Person'] = array('id' => $people[$i]['id'], 'age' =>
> >>>>> $people[$i]['age']);
> >>>>>   $data['Country'] = array('name' =>  $people[$i]['country']);
>
> >>>>>   $this->Person->saveAll($data);
> >>>>> }
>
> >>>>> However, the third person is not saved and no error is reported. I
> >>>>> would expect for CakePHP to get the id of Belgium and save the third
> >>>>> person with this id in the countries_id field. Obviously I do not
> >>>>> understand the associations completely yet. Please help.
>
> >>>>> Thanks!
>
> >>>>> Here is My SQL log if you need it:
>
> >>>>> Query   Affected        Num. rows       Took (ms)       Actions
> >>>>> SELECT COUNT(*) AS `count` FROM `countries` AS `Country` WHERE
> >>>>> `Country`.`name` = 'Belgium'    1       1       1
>
> >>>>> SELECT COUNT(*) AS `count` FROM `countries` AS `Country` WHERE
> >>>>> `Country`.`name` = 'Belgium'    1       1       1
>
> >>>>> INSERT INTO `countries` (`name`) VALUES ('Belgium')     1       1       1
> >>>>> SELECT COUNT(*) AS `count` FROM `people` AS `Person` WHERE
> >>>>> `Person`.`id` = 1       1       1       2       maybe slow
>
> >>>>> INSERT INTO `people` (`id`, `age`, `countries_id`) VALUES (1, 23, 1)    1
> >>>>> 1       1
> >>>>> SELECT COUNT(*) AS `count` FROM `countries` AS `Country` WHERE
> >>>>> `Country`.`name` = 'Austria'    1       1       1
>
> >>>>> SELECT COUNT(*) AS `count` FROM `countries` AS `Country` WHERE
> >>>>> `Country`.`name` = 'Austria'    1       1       1
>
> >>>>> INSERT INTO `countries` (`name`) VALUES ('Austria')     1       1       1
> >>>>> SELECT COUNT(*) AS `count` FROM `people` AS `Person` WHERE
> >>>>> `Person`.`id` = 2       1       1       1
>
> >>>>> INSERT INTO `people` (`id`, `age`, `countries_id`) VALUES (2, 12, 2)    1
> >>>>> 1       1
> >>>>> SELECT COUNT(*) AS `count` FROM `countries` AS `Country` WHERE
> >>>>> `Country`.`name` = 'Belgium'    1       1       1
>
> >>>>> --
> >>>>> Our newest site for the community: CakePHP Video Tutorials
>
> >>>>http://tv.cakephp.org> Check out the new CakePHP Questions sitehttp://ask.cakephp.organdhelp
>
> >>>> others with their CakePHP related questions.
>
> >>>>> To unsubscribe from this group, send email to
> >>>>> cake-php+unsubscribe@googlegroups.com For more options, visit this group
>
> >>>> athttp://groups.google.com/group/cake-php
>
> >>>> --
> >>>> --
> >>>> Lep pozdrav, Tilen Majerlehttp://majerle.eu
>
> >>> --
> >>> Our newest site for the community: CakePHP Video Tutorialshttp://tv.cakephp.org
> >>> Check out the new CakePHP Questions sitehttp://ask.cakephp.organdhelp others with their CakePHP related questions.
>
> >>> To unsubscribe from this group, send email to
> >>> cake-php+unsubscribe@googlegroups.com For more options, visit this group athttp://groups.google.com/group/cake-php
>
> > --
> > Our newest site for the community: CakePHP Video Tutorialshttp://tv.cakephp.org
> > Check out the new CakePHP Questions sitehttp://ask.cakephp.organd help others with their CakePHP related questions.
>
> > To unsubscribe from this group, send email to
> > cake-php+unsubscribe@googlegroups.com For more options, visit this group athttp://groups.google.com/group/cake-php

--
Our newest site for the community: CakePHP Video Tutorials http://tv.cakephp.org
Check out the new CakePHP Questions site http://ask.cakephp.org and help others with their CakePHP related questions.


To unsubscribe from this group, send email to
cake-php+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/cake-php

No comments: