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 
ida 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 | 8285
 
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)