Nette/Database (NotORM) a editace M:N vazeb
- misablaha@gmail.com
- Člen | 1
Ahoj,
potřeboval bych nějaké typy k M:N vazbám.
Je to sice popisováno v každém článku o NotORM, nicméně všude se
řeší jen čtení a nedaří se mi dopracovat k efektivnímu řešení
editace, vkládání a mazání.
mám následující tabulky:
user: id, name, ...
property: id, name, ...
user_property: user_id, property_id, value
Tabulka user obsahuje řádově stovky tisíc řádků, a každý user má
desítky až stovky properties, proto potřebuji minimalizovat počet
pokládaných dotazů.
Změny se provádějí formou „vlastnosti uživatele uveď do stavu:“.
Rád bych se dostal k následujícím SQL dotazům:
// načtu skupinu uživatelů kterou upravuji
SELECT * FROM user WHERE id IN (3, 5, 8, 9, ...)
// ideálně: načtu vazby pro celou skupinu
SELECT * FROM user_property WHERE user_id IN (3, 5, 8, 9, ...)
// případně: pro každého uživatele načtu jeho vazby
SELECT * FROM user_property WHERE user_id = 3
// prováděné změny zaměřit podle kombinace user_id + property_id (které reálně tvoří primární klíč)
// je to vůbec možné, nebo je nutné doplnit (informačně zbytečný) sloupec "id"?
UPDATE user_property SET value = 'hodnota' WHERE user_id = 3 AND property_id = 13
// kvůli cizím klíčům ověřit existenci příslušných properties
SELECT * FROM property WHERE id IN (15, 16, ...)
// vytvořit záznamy pro chybějící property
INSERT INTO property (id) VALUES (15), (16), ...
// v jediném příkazu vložit všechny nové záznamy
INSERT INTO user_property (user_id, property_id, value) VALUES (3, 15, 'hodnota'), (3, 16, 'hodnota'), ...
// ideálně: všechny rušené záznamy odstranit v jediném příkazu
DELETE FROM user_property WHERE (user_id = 3 AND property_id = 11) OR (user_id = 3 AND property_id = 14) ...
// případně: záznamy rušit v blocích podle uživatele
DELETE FROM user_property WHERE user_id = 3 AND property_id IN (11, 14, ...)
Nedělám si iluze, že tohle zvládnu bez potřeby poskládat si dotaz ručně. Nicméně předpokládám, že něco z toho NotORM dokáže samo :-)
- vrana
- Člen | 131
Ideální use case pro NotORM:
<?php
$delete = array();
// načtu skupinu uživatelů kterou upravuji
foreach ($db->user("id", array(3, 5, 8, 9)) as $user) {
// ideálně: načtu vazby pro celou skupinu
$user_properties = $user->property();
foreach ($user_properties as $property) {
}
// prováděné změny zaměřit podle kombinace user_id + property_id (které reálně tvoří primární klíč)
$user_properties->where("property_id", 13)->update(array(
"value" => "hodnota",
));
// kvůli cizím klíčům ověřit existenci příslušných properties
$properties = $db->property(array(15, 16));
// vytvořit záznamy pro chybějící property
$properties->insert(
array("id" => 15),
array("id" => 16)
);
// v jediném příkazu vložit všechny nové záznamy
$user_properties->insert(
array("property_id" => 15, "value" => "hodnota"),
array("property_id" => 16, "value" => "hodnota")
);
$delete[] = new NotORM_Literal("(3, 11)");
$delete[] = new NotORM_Literal("(3, 14)");
// případně: záznamy rušit v blocích podle uživatele
// $user_properties->where("property_id", array(11, 14))->delete();
}
// ideálně: všechny rušené záznamy odstranit v jediném příkazu
$db->user_property("(user_id, property_id)", $delete)->delete();
?>
Ty properties bych si načetl před začátkem cyklu všechny do pole, které bych vevnitř cyklu udržoval, ať se pokaždé nemusí načítat znovu.
- Michal Blaha
- Člen | 2
Díky za vyčerpávající řešení.
Jako na potvoru používám Nette\Connection a to zkolabuje na
tomhle místě:
vrana napsal(a):
<?php $user_properties->where("property_id", 13)->update(array( "value" => "hodnota", )); ?>
NotORM funguje bez problémů :-).
Sice se vynořilo několik jiných problémů spojených s používáním
PostgeSQL, ale týká se to jen formátování dotazů … s tím se přesunu
na github.
A něco postřehů z vlastního postupu:
- Vazební tabulku jsem doplnil o sloupec
id
a pomocí triggeru ho nastavuji na text:$id1_$id2
. Takže jsem schopen si celý výsledek načíst do pole a pak k tomu přistupovat podle klíčů - Přičemž hledání podle textového sloupce je zhruba stejně rychlé jako hledání podle 2 sloupců číselných. (pro potřeby editace, nebo mazání)
… čímž se zbavím poměrně magického načítání vazebních tabulek
Editoval Michal Blaha (2. 5. 2011 1:15)
- David Grudl
- Nette Core | 8228
Michal Blaha napsal(a):
a to zkolabuje na tomhle místě:
Co myslíš tím zkolabuje?
- Oggy
- Člen | 306
vrana napsal(a):
<?php
> $user_properties->where("property_id", 13)->update(array(
> "value" => "hodnota",
> ));
?>
při pokusu updatnout M:N záznam dostávám pořád NOTICE o neexistenci indexu row[‚id‘] ..
např.
<?php
foreach($application->application_tag() as $application_tag) {
$application_tag->update(array('neco'=>5,'necojineho'=>4));
}
?>
vyžaduje to mít primární klíč id..zde je primarni klic kombinaci application_id,tag_id ..
je chyba někde u mě? nebo je toto požadované chování?
Editoval Oggy (11. 1. 2012 22:52)