Nette database table více tabulek, join přes cizí klíč, nikoliv primární
- Rafan
- Člen | 17
Dobrý den,
už od včerejška se peru s Nette Database Table. V krátkosti popíšu strukturu tabulek a data které bych z nich chtěl dostat
Tabulka – orders:
id | … |
Tabulka orders_products:
id | product_id | order_id | … |
Tabulka products_images
product_id | … |
Zde je můj kód pro získání dat v PHP
$getOrders = $this->context->table("orders");
foreach ($getOrders as $order)
{
echo $order->name;
foreach($order->related("orders_products") as $op)
{
$image = $op->ref("products_images", "product_id");
}
}
z proměnné $image je patrné, že se chci dostat k tabulce products_images přes cizí klíč orders_products .product_id, ale mysql dotaz mi tam stále dává where id in.
Takto vypadá SQL dotaz se kterým nejsem spokojený:
SELECT *
FROM `products_images`
WHERE (`id` IN (58967, 58966))
Takto bych chtěl aby vypadal:
SELECT *
FROM `products_images`
WHERE (`product_id` IN (58967, 58966))
Funguje to ve chvíli kdy z tabulky products_images vyhodím primary key id a jako primary key dám product_id.
Jak to prosím mohu ovlivnit? Je můj přístup úplně mimo? Vím jak bych požadovaného výsledku dosáhl klasicky přes \Nette\Database\Connection.
Děkuji za Váš čas.
- Rafan
- Člen | 17
Upravil jsem kód a nyní mi vyhazuje Tracy:
No reference found for $orders_products->related(products_images).
Je teda zřejmé že mám něco špatně napříč těmi FK.
Přidám zde show create table tabulek orders_products a products_images (odstranil jsem přebytečné sloupce)
CREATE TABLE `orders_products` (
PRIMARY KEY (`id`),
KEY `order_id` (`order_id`),
KEY `product_id` (`product_id`),
CONSTRAINT `orders_products_ibfk_2` FOREIGN KEY (`order_id`) REFERENCES `orders` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `orders_products_ibfk_3` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=276 DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci
CREATE TABLE `products_images` (
`id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`),
KEY `product_id` (`product_id`),
CONSTRAINT `products_images_ibfk_1` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci
Pokud by jste měl chvilku čas se na to podívat, byl bych velmi
vděčný.
Děkuji.
- CZechBoY
- Člen | 3608
Mně to jede jak jsem psal
/** @var ActiveRow $order */
foreach ($orders as $order) {
echo $order->name;
/** @var ActiveRow $op */
foreach ($order->related('orders_products') as $op) {
/** @var ActiveRow $pi */
foreach ($op->related('products_images', 'product_id') as $pi) {
var_dump($pi->toArray());
}
}
}
CREATE TABLE `orders` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) COLLATE utf8_czech_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci;
CREATE TABLE `orders_products` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`order_id` int(11) NOT NULL,
`product_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `order_id` (`order_id`),
KEY `product_id` (`product_id`),
CONSTRAINT `orders_products_ibfk_1` FOREIGN KEY (`order_id`) REFERENCES `orders` (`id`) ON DELETE CASCADE,
CONSTRAINT `orders_products_ibfk_2` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci;
CREATE TABLE `products` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) COLLATE utf8_czech_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci;
CREATE TABLE `products_images` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`product_id` int(11) NOT NULL,
`image` varchar(32) COLLATE utf8_czech_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `product_id` (`product_id`),
CONSTRAINT `products_images_ibfk_1` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci;
- Rafan
- Člen | 17
Děkuji, chyběl mi tam parametr product_id v related. Vím, že toto řešení jsem už také zkoušel a problém je zde takový, že sice referenci najde ale v klauzuli IN jsou špatné hodnoty, protože tam vkládá hodnoty orders_products.id a ne orders_products.product_id.
hodnoty v tabulce orders_products:
|id|order_id|product_id|
|274|163|58967|
|275|163|58966|
PHP kód
foreach($orders_products->related("products_images", "product_id") as $products_images){}
Výsledek:
SELECT *
FROM `products_images`
WHERE (`products_images`.`product_id` IN (274, 275))
Dá se toto nějak ovlivnit?
- Rafan
- Člen | 17
Bohužel to už jsem také zkoušel:
$getOrders = $this->context->table("orders");
foreach ($getOrders as $order)
{
foreach($order->related("orders_products") as $orders_products)
{
echo $orders_products->name;
foreach($orders_products->related("products", "id") as $p)
{
echo $p->price_vat; //nic nevypíše
}
}
}
opět při dotazu na tabulku products dosazuje jako spojovací klíč orders_products.id nikoliv orders_products.product_id.
SELECT `id`
FROM `products`
WHERE (`products`.`id` IN (274, 275))
Zřejmě použití nette database není pro můj případ vhodné?
Děkuj za info.
- Rafan
- Člen | 17
Také to mám v modelu (naplním si pole které metoda vrátí a pole pak používám v šabloně). Použití v šabloně se mi nelíbí, ale líbí se mi způsob výběru dat a spojení tabulek. Jinak to řeším tak, že si vyberu z tabulky orders na základě id vyberu produkty a k nim obrázky (klasicky přes left outer join), tím si naplním pole které metoda v modelu vrací. Mě se u tohoto způsobu líbilo že nemusím řešit joiny apod.
No ale budu se muset držet svého obvyklého postupu. I tak moc děkuji za pomoc.