上周我开始使用Doctrine而且我非常积极,但我遇到了一些问题。我正在MySQL中实现分层数据:http://ftp.nchu.edu.tw/MySQL/tech-resources/articles/hierarchical-data.html并且我需要一些聚合的实体(不确定这是否是正确的术语,也许虚拟更好)。但是我需要两个额外的字段,即:Depth和ParentID。目前(使用本机查询)我通过子查询获取这些。 Doctrine的结果是一个数组,我想要一个对象。
这是我正在使用的表结构:
CREATE TABLE IF NOT EXISTS `category` (
`ID` int(8) unsigned NOT NULL AUTO_INCREMENT,
`Name` varchar(45) NOT NULL,
`LeftID` int(10) NOT NULL,
`RightID` int(10) NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ;
三个示例类别:
INSERT INTO `category` (`ID`, `Name`, `LeftID`, `RightID`) VALUES
(1, 'cat#1', 1, 4),
(2, 'cat#2', 5, 6),
(3, 'cat#1.1', 2, 3);
我查看了doctrine(http://doctrine-orm.readthedocs.org/en/latest/cookbook/aggregate-fields.html)中的聚合字段示例,但我不清楚实际的实现。如果它和我想要的一样。
我现在使用的实体看起来像这样:
/**
* @ORM\Entity (repositoryClass="Application\Entity\CategoryRepository")
* @ORM\Table(name="category")
*/
class Category
{
protected $inputFilter;
/**
* @ORM\Id
* @ORM\Column(type="integer");
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $ID;
/**
* @ORM\Column(type="string")
*/
protected $Name;
/**
* @ORM\Column(type="integer")
*/
protected $LeftID;
/**
* @ORM\Column(type="integer")
*/
protected $RightID;
}
我正在使用魔术setter / getter来公开受保护的属性(__set& __get),以接收我使用以下查询的数据:
SELECT
node.ID,
node.Name,
node.LeftID,
node.RightID,
(
SELECT
ID
FROM
Category subtree
WHERE
subtree.LeftID < node.LeftID
AND
subtree.RightID > node.RightID
ORDER BY
subtree.RightID - node.RightID ASC
LIMIT
0, 1
) AS ParentID,
(
SELECT
(COUNT(parent.ID) - 1)
FROM
Category AS node,
Category AS parent
WHERE
node.LeftID BETWEEN parent.LeftID AND parent.RightID
AND
node.ID = 3
GROUP BY
node.ID
ORDER BY
parent.LeftID
) As Depth
FROM
Category As node,
Category As parent
WHERE
node.ID = 3
AND
node.LeftID BETWEEN parent.LeftID AND parent.RightID
GROUP BY
node.ID
结果(使用给定的数据集)将是:
ID Name LeftID RightID ParentID Depth
3 cat#1.1 2 3 1 1
这正是我想要在Doctrine实体中拥有的结果,但找不到将实体作为Doctrine对象的解决方案。目前我有双重功能,一个给出我真正需要Depth和ParentID的数组,如果我需要对象,我使用默认的doctrine函数(例如find),但我希望有一个优雅的解决方案。此外,我想我将来还需要其他对象,例如:人的年龄(从生日算起)。
答案 0 :(得分:0)
这应该可以得到你想要的东西(可能需要修改一下):
$manager = $this->getDoctrine()->getEntityManager();
$qb = $manager->createQueryBuilder();
$expr = $qb->expr();
$query = $qb
->select('node.ID, node.Name, node.LeftID, node.RightID')
->addSelect('
(SELECT
ID
FROM
Category subtree
WHERE
subtree.LeftID < node.LeftID
AND
subtree.RightID > node.RightID
ORDER BY
subtree.RightID - node.RightID ASC
LIMIT
0, 1) AS ParentID
')
->addSelect('
(SELECT
(COUNT(parent.ID) - 1)
FROM
Category AS node,
Category AS parent
WHERE
node.LeftID BETWEEN parent.LeftID AND parent.RightID
AND
node.ID = 3
GROUP BY
node.ID
ORDER BY
parent.LeftID
) As Depth
')
->from('Category', 'node')
->join('Category', 'parent')
->where($expr->eq('node.ID', 3))
->andWhere($expr->between('node.LeftID', 'parent.LeftID', 'parent.RightID'))
->groupBy('node.ID')
->getQuery();
$result = $query->getArrayResult();
编辑:没关系。刚注意到你需要一个对象,而不是一个数组......
您可能希望查看此Doctrine扩展名:https://github.com/Atlantic18/DoctrineExtensions/blob/master/doc/tree.md
或者,作为替代方法,使用您需要的字段创建一个新的对象类,将其标记为ReadOnly for Doctrine并为其创建自定义查询(您可以使用带有Doctrine的虚拟表进行阅读)。