Relationship 1:1 v Nextras / ORM

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
majo
Člen | 21
+
0
-

Caute,

snazim sa pochopit Nextras/ORM (2.2) a zatial vsetko v pohode, az kym som neprisiel na relationships.

Mam 2 tabulky user a user_password (a vytvorene 2 entity, ktore su zapisane aj v UserRepository)

user tabulke su nejake data s primarny klucom v stlpci id

potrebujem ziskat data s user_password ktory obsahuje stlpec user_id ($user->password->nejaka_property_s_userPassword)

Vztah je: 1 uzivatel ma 1 heslo (OneHasOne) – dovodom je, ze uzivatel sa moze prihlasovat viacerymi sposobmi, heslo je len jedno z nich, preto som to oddelil

/**
 * User
 *
 * @property int                        $id          		{primary}
 * @property string                     $username
 * @property string                 	$role
 * @property int	             	    $active
 *
 * @property UserPassword 				$password 			{1:1 UserPassword::$user_id}
 */
class User extends Entity
{
}
/**
 * UserPassword
 *
 * @property int                        $id          	{primary}
 *
 * @property User 						$user_id 		{1:1 User::$id}
 *
 * @property string                     $password
 * @property int                     	$attempts
 * @property DateTime 					$last_attempt
 */
class UserPassword extends Entity
{
}

cize takto nejak som to vydedukoval, co mi ale vyhodi chybu:

OrmDemo\User::$password relationship with OrmDemo\UserPassword::$user_id is not symetric.

Viem, ze to je urcite cele zle, doteraz som „vyuzival“ doctrine a tam to nejak podobne islo.. Nenakopne ma niekto (nie do guli) tym spravnym smerom?

majo
Člen | 21
+
0
-

uz som nacisto bezradny, mozog mam zacykleny, uz fakt neviem co dalej, videl som snad vsetky exceptions ktore su tam, a neviem nato prist..

dokopal som to do „funkcnosti“, ze s entity User data vytiahnem bez problemu, ale s UserPassword nikoli..

pridal som property „password“ na skusku do entity User ci to pojde (a ide), lenze ja chcem aby bol klucom ID, ale budiz..

/**
 * User
 *
 * @property int 							$id 				{primary}
 * @property string                     	$username
 * @property string                 	    $role
 * @property string             	        $active
 *
 * @property UserPassword 					$password 			{1:1 UserPassword::$user_id, isMain=true}
 *
 */
class User extends Entity
{

}
/**
 * UserPassword
 *
 * @property int 						$id 			{primary}

 * @property User 						$user_id 		{1:1 User::$password}
 *
 * @property string                     $password
 * @property int                     	$attempts
 * @property DateTime 					$last_attempt
 *
 */
class UserPassword extends Entity
{

}

pri pokuse:

$this->user = $this->orm->user->findBy(['username' => 'admin'])->fetch();

je vsetko OK, udaje sa nacitaju.

nasledne pri pokuse:

$this->user->password

zahlasi chybu: Undefined property App\Model\User::$user_id.

a vytvara dotazy:

SELECT `user`.* FROM `user` AS `user` WHERE `user`.`username` = 'admin'
SELECT `user`.* FROM `user` AS `user` WHERE `id` IN (1)

kde hodnota v zatvorke je vlastne hodnota stlpca password v tabulke User.. tak som si chcel overit ci je nutne mat iny stlpec vztahu medzi tymi dvoma tabulkami ako primarny kluc kde mi vyhadzovalo chybu ze „property musi mat moznost byt nulova“.. ale primarny kluc predsa nemoze byt nulovy..

uz viac asi nepokrocim.. nikto kto by mi povedal kde robim chybu??

JZechy
Člen | 161
+
+1
-

@majo Nextras automaticky zbavuje sloupce sufixu _id, takže atributu by měl stačit název user.

Jinak, ono to poprvé je opravdu takové vyšší dívčí nastavovat poprvé vztahy mezi entitami, ale jak jich pár nastavíš, pak už pochopíš, jak to tam chodí, já zprvu taky strávil nad některými vztahy věky :D

Editoval JZechy (7. 2. 2017 20:22)

hrach
Člen | 1838
+
+1
-

@majo myslim, ze v dokumentaci to zase tak spatne neni, kdyz mrknes sem: http://nextras.org/…elationships#… tak je videt, ze zadny _id se tam nepridava a nad kodem taky je napsano, ze ten sloupec se realne jmenuje se suffixem _id a ve ktere tabulce je, kdyz je ta strana primary. Ale zkusim tu doc vylepsit. Pripadne sem napis jaka exception ta je s jakym zapisem.

majo
Člen | 21
+
0
-

ok, takze som vyhodil s anotacii ten suffix _id a na password pridal do db..

User ma:

* User
* @property UserPassword|NULL			$password 			{1:1 UserPassword::$user, isMain=true}

v databazi user upraveny nazov stlpca na password_id

* UserPassword
* @property User 						$user 		{1:1 User::$password}

v databaze user_password je nazov stlpca user_id

v tabulke je momentalne 1 zaznam user (password_id = 1) a 1 zaznam user_password (user_id = 1) ..

pri pokuse ziskat data s user:

$this->user = $this->orm->user->getById(1);

je vsetko v poriadku, az kym nesiahnem na property password

$this->user->password; // vrati NULL

mozno som uz blizko, alebo je aj dost mozne, ze som nieco dolezite nepochopil…

taktiez je podstatne, ze potrebujem aby bol primarny kluc $id v user klucom pre druhu tabulku kde su hesla (user_id) . Momentalna property password je len z dovodu, ze mi to zatial inak neslo.

A teda, ked urobim relationship na User::$id x UserPassword::$user dostanem chybu:

`Nextras\Orm\NullValueException

Property App\Model\User::$id is not nullable.`

Primarny kluc ale nemoze byt NULL.

Co sa tyka dokumentacie, je super. Len pri tebou odkazovanej pasazi (1:1 obojsmerne) ma plietla ta entita Ean a pritom je tam definovana entita Tag. Preto som skusal vydedukovat spravnu funkcnost, ku ktorej som sa zatial nedopatral :(

Editoval majo (8. 2. 2017 10:09)

hrach
Člen | 1838
+
0
-

@majo to, jak to mas definovany a jak to pouzivas uz vypada spravne. Jaky sql dotaz to spusti? a kdyz ho spustit sam rucne, vrati ti to? A smazal si cache?

majo
Člen | 21
+
0
-

ked spustim nieco taketo:

$this->user = $this->orm->user->getById(1);
var_dump($this->user->password);

tak var_dump je NULL. ale $this->user normalne obsahuje data s tabulky user..

V tracy je jediny dotaz:
SELECT `user.* FROM user AS user WHERE user.id = 1 LIMIT 1`

tabulka user:
CREATE TABLE `user (
id int(11) NOT NULL,
username varchar(60) COLLATE utf8_slovak_ci NOT NULL,
role varchar(255) COLLATE utf8_slovak_ci NOT NULL,
active tinyint(1) NOT NULL,
password_id int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_slovak_ci;

INSERT INTO user (id, username, role, active, password_id) VALUES
(1, ‚admin‘, ‚user,admin‘, 1, 1);`

Tabulka user_password:
CREATE TABLE `user_password (
id int(11) NOT NULL,
user_id int(11) NOT NULL,
password varchar(60) COLLATE utf8_slovak_ci NOT NULL,
attempts int(3) NOT NULL,
last_attempt datetime DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_slovak_ci;

INSERT INTO user_password (id, user_id, password, attempts, last_attempt) VALUES
(1, 1, ‚$2y$10$QPEXXD8HM98bmHl6jkqPj.g7KTip9tQtLSd4rgn62frN/.045orRW‘, 0, NULL);`

cache premazavam vzdy pred nejakou zmenou..

Editoval majo (8. 2. 2017 11:56)

majo
Člen | 21
+
0
-

ak zmenim s MyISAM na InoDB a nastavim:

ALTER TABLE `user
ADD CONSTRAINT user_ibfk_1 FOREIGN KEY (password_id) REFERENCES user_password (user_id);`

a

ALTER TABLE `user_password
ADD CONSTRAINT user_password_ibfk_1 FOREIGN KEY (user_id) REFERENCES user (password_id);`

tak na $this->user->password prebehnu tieto dotazy:
SELECT `user.* FROM user AS user WHERE user.id = 1 LIMIT 1
SELECT user.* FROM user AS user WHERE id IN (1)`

a vyhodi exception:

Nextras\Orm\InvalidArgumentException

Undefined property App\Model\User::$user.
majo
Člen | 21
+
+1
-

edit: DOBOJOVANE, MAM TO :D … ja som bol v tom, ze mozem mat viac entit v ramci jedneho repository.. ked som vytvoril UserPasswordRepository a UserPasswordMapper tak to uz ide..

Editoval majo (8. 2. 2017 18:54)

majo
Člen | 21
+
0
-

caute, dnes som sa k tomu vratil, a aj tak mi to nejde akoby malo..

Relationships je nastavene spravne… ale ked chcem vytiahnut nejake data tak mi to vzdy vrati bud NULL (v pripade 1:1 – tu ani nezada dotaz do DB) alebo objekt Nextras\Orm\Relationships\OneHasMany (v pripade 1:M), ktory je bez vysledkov (zistene cez ->count() ).

Dotaz sa vygeneruje spravne, napr.

SELECT `user`.* FROM `user` AS `user` WHERE `user`.`username` = 'admin' LIMIT 1
SELECT `user_permanent`.* FROM `user_permanent` AS `user_permanent` WHERE `user_permanent`.`user_id` IN (1)

ked druhy dotaz spustim v phpmyadmin tak mi bez problemu zobrazi vysledky ako maju byt..

je nejaky rozdiel ked pouzivam MyISAM alebo InnoDB s nastavenymi klucmi? Lebo ak aj nastavim kluce v InnoDB rovnako ako mam zapisane v entitach, tak je vysledok rovnaky (teda ziadny).

Dotaz:

SELECT CONSTRAINT_NAME, COLUMN_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = DATABASE() AND REFERENCED_TABLE_NAME IS NOT NULL AND TABLE_NAME = 'user_permanent'

v phpmyadmin nevrati nic…

tak uz som fakt ze bezradny..

Editoval majo (9. 2. 2017 19:02)

majo
Člen | 21
+
0
-

skusim este ako posledny pokus polozit posledne otazky, ostatne su uz pase..

ak pri vztahu 1:1 vytvorim v tabulke user stlpec s nazvom property v ktorej definujem tento vztah, a zadam lubovolnu hodnotu vznikne takyto dotaz:

SELECT user_password.* FROM user_password AS user_password WHERE id IN (1)

kde hladana hodnota (1) je vlastne hodnota s toho vytvoreneho stlpca a hlada sa v stlpci ID, pritom definovany je stlpec UserPassword::$USER_ID .. to je bug alebo feature?

ak tento stlpec zrusim, tak sa ziadny dotaz do DB nevytvori a property s definiciou vztahu dostane rovno NULL, aj ked existuje

pri vztahu 1:M a neexistencii stlpca s nazvom property v ktorej definujem vztah vznikne dotaz:

SELECT user_permanent.* FROM user_permanent AS user_permanent WHERE user_permanent.user_id IN (2)

pricom hladana hodnota je v poriadku (primarny kluc uzivatela), tak isto aj definovany stlpec v druhej tabulke.. avsak nevrati ziadny vysledok, aj ked su zaznamy v tabulke..

ak vytvorim stlpec a zadam nejaku hodnotu skonci to chybou:
TypeError

Argument 1 passed to Nextras\Orm\Relationships\HasMany::set() must be of the type array, integer given, called in D:\www\nette\nette\vendor\nextras\orm\src\Relationships\HasMany.php on line 77

dva uplne odlisne spravania… je to bug, feature, alebo som blby ja?

Editoval majo (9. 2. 2017 20:03)