I am attempting what I call a double join. Let me describe what I'm trying to do, then we'll dive into the meat of it.
I have a table called Matches that has three fields
id, character1_id, character2_id.
I have another table called charnames that has only two fields.
id, charname.
For example sake, let's say that this is to track tennis matches between people. So in 'Charnames' I have a bunch of id's and a bunch of names.
1 Jeremy
2 Bob
3 Gandalf
4 Frodo
And 'Matches' pairs them up by id.
1 3 4
2 1 2
So if I queried this and joined it, I'd get something like this:
Match 1: Gandalf(3) and Frodo(4)
Match 2: Jeremy(1) and Bob(2)
(We'll tackle triple joins later! ugh!)
And that's it. The trick is that I have to join it twice, because 'Matches' contains two character fields, both of which tie back to the primary key index on 'Charnames'.
So here's the code involved at the moment (which is not working), and all the assorted details.
YAML for 'Charnames'
ORM\Testing\Charnames:And the entity file for 'Charnames'
type: entity
table: test_charnames
fields:
id:
type: integer
id: true
generator:
strategy: AUTO
charname:
type: string
length: 255
Table structure:
<?php
namespace ORM\Testing;
use Doctrine\ORM\Mapping as ORM;
/**
* ORM\Testing\Charnames
*/
class Charnames
{
/**
* @var integer $id
*/
private $id;
/**
* @var string $charname
*/
private $charname;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set charname
*
* @param string $charname
* @return Charnames
*/
public function setCharname($charname)
{
$this->charname = $charname;
return $this;
}
/**
* Get charname
*
* @return string
*/
public function getCharname()
{
return $this->charname;
}
}
CREATE TABLE IF NOT EXISTS `test_charnames` (And now 'Matches'. YAML first.
`id` int(11) NOT NULL AUTO_INCREMENT,
`charname` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=11 ;
ORM\Testing\Matches:Entity file:
type: entity
table: test_matches
fields:
id:
type: integer
id: true
generator:
strategy: AUTO
manyToOne:
character1:
targetEntity: ORM\Testing\Charnames
character2:
targetEntity: ORM\Testing\Charnames
<?phpTable Structure:
namespace ORM\Testing;
use Doctrine\ORM\Mapping as ORM;
/**
* ORM\Testing\Matches
*/
class Matches
{
/**
* @var integer $id
*/
private $id;
/**
* @var ORM\Testing\Charnames
*/
private $character1;
/**
* @var ORM\Testing\Charnames
*/
private $character2;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set character1
*
* @param ORM\Testing\Charnames $character1
* @return Matches
*/
public function setCharacter1(\ORM\Testing\Charnames $character1 = null)
{
$this->character1 = $character1;
return $this;
}
/**
* Get character1
*
* @return ORM\Testing\Charnames
*/
public function getCharacter1()
{
return $this->character1;
}
/**
* Set character2
*
* @param ORM\Testing\Charnames $character2
* @return Matches
*/
public function setCharacter2(\ORM\Testing\Charnames $character2 = null)
{
$this->character2 = $character2;
return $this;
}
/**
* Get character2
*
* @return ORM\Testing\Charnames
*/
public function getCharacter2()
{
return $this->character2;
}
}
CREATE TABLE IF NOT EXISTS `test_matches` (Here is the data actually in my tables:
`id` int(11) NOT NULL AUTO_INCREMENT,
`character1_id` int(11) DEFAULT NULL,
`character2_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `IDX_DA67C172F6129E9E` (`character1_id`),
KEY `IDX_DA67C172E4A73170` (`character2_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ;
test_matches:
id character1_id character2_idtest_charnames:
1 7 2
2 8 4
3 10 3
4 2 1
1 Gandalf
2 Gollum
3 Bilbo
4 Frodo
5 Samwise
6 Gimili
7 Legolas
8 Thorin
9 Saurumon
10 Treebeard
And now, some querying and code.
Here is my query at present:
$query = $this -> doctrine -> em -> createQuery ("SELECT a.id, b.charname, c.charname
FROM ORM\Testing\Matches a
JOIN a.character1 b
JOIN a.character2 c
");
$result = $query->getResult();
\Doctrine\Common\Util\Debug::dump($result);
This returns the following data:
array(4) {So it is returning the 2nd character name. But not the first.
[0]=> array(2) { ["id"]=> int(1) ["charname"]=> string(6) "Gollum" }
[1]=> array(2) { ["id"]=> int(2) ["charname"]=> string(5) "Frodo" }
[2]=> array(2) { ["id"]=> int(3) ["charname"]=> string(5) "Bilbo" }
[3]=> array(2) { ["id"]=> int(4) ["charname"]=> string(7) "Gandalf" } }
I also tried this query:
$query = $this -> doctrine -> em -> createQuery ("SELECT a, b, cAnd the output:
FROM ORM\Testing\Matches a
JOIN a.character1 b
JOIN a.character2 c
");
array(4) {So, I *think* that the problem is with my query. But its entirely possible that it is a problem with my entities or table structure.
[0]=> object(stdClass)#42 (4) { ["__CLASS__"]=> string(19) "ORM\Testing\Matches" ["id"]=> int(1) ["character1"]=> string(21) "ORM\Testing\Charnames" ["character2"]=> string(21) "ORM\Testing\Charnames" }
[1]=> object(stdClass)#71 (4) { ["__CLASS__"]=> string(19) "ORM\Testing\Matches" ["id"]=> int(2) ["character1"]=> string(21) "ORM\Testing\Charnames" ["character2"]=> string(21) "ORM\Testing\Charnames" }
[2]=> object(stdClass)#72 (4) { ["__CLASS__"]=> string(19) "ORM\Testing\Matches" ["id"]=> int(3) ["character1"]=> string(21) "ORM\Testing\Charnames" ["character2"]=> string(21) "ORM\Testing\Charnames" }
[3]=> object(stdClass)#73 (4) { ["__CLASS__"]=> string(19) "ORM\Testing\Matches" ["id"]=> int(4) ["character1"]=> string(21) "ORM\Testing\Charnames" ["character2"]=> string(21) "ORM\Testing\Charnames" } }
Jerm, this is a 'left join', using the two different fields in the 'matches' table for each join to get the appropriate names. For example, here's my test in a local mysql database:
ReplyDeletemysql> select matches.id, a.charname, b.charname
-> from
-> matches
-> left join charnames a on matches.character1_id = a.id
-> left join charnames b on matches.character2_id = b.id
-> ;
+----+-----------+----------+
| id | charname | charname |
+----+-----------+----------+
| 1 | Legolas | Gollum |
| 2 | Thorin | Frodo |
| 3 | Treebeard | Bilbo |
| 4 | Gollum | Gandalf |
+----+-----------+----------+
4 rows in set (0.00 sec)
Thanks Dave.
ReplyDeleteI tried changing them to left joins, like so:
$query = $this -> doctrine -> em -> createQuery ("SELECT a.id, b.charname, c.charname
FROM ORM\Testing\Matches a
LEFT JOIN a.character1 b
LEFT JOIN a.character2 c
");
But I get the same results as before. Doctrine is not digging it.
To test, I tried removing entirely the reference to 'c', so I removed 'c.charname', and 'JOIN a.character2 c', and it spit out a join of the character1 part. but I still can't quite get the whole thing to jive.
Here's the documentation relative to this kind of query. It even shows a simple LEFT JOIN...
ReplyDeletehttp://readthedocs.org/docs/doctrine-orm/en/latest/reference/dql-doctrine-query-language.html