首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >理论聚合/虚拟列

理论聚合/虚拟列
EN

Stack Overflow用户
提问于 2014-11-17 16:53:24
回答 1查看 2K关注 0票数 2

上周我开始使用Doctrine,我对此非常肯定,但我遇到了一些问题。我在MySQL:http://ftp.nchu.edu.tw/MySQL/tech-resources/articles/hierarchical-data.html中实现分层数据,我拥有的实体需要一些聚合(不确定这是不是正确的术语,也许虚拟更好)。但我需要两个额外的字段,即: Depth和ParentID。目前(使用原生查询),我通过子查询获取这些内容。Doctrine的结果是一个数组,而我想要一个对象。

这是我正在使用的表结构:

代码语言:javascript
运行
复制
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 ;

和三个示例类别:

代码语言:javascript
运行
复制
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)中的聚合字段示例,但我并不清楚真正的实现。另外,如果它是相同的,我想要的。

我现在使用的实体看起来像这样:

代码语言:javascript
运行
复制
/**
 * @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),以接收我使用以下查询的数据:

代码语言:javascript
运行
复制
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

结果(对于给定的数据集)将是:

代码语言:javascript
运行
复制
ID  Name    LeftID  RightID     ParentID    Depth   
3   cat#1.1     2   3           1           1

这正是我想在Doctrine实体中得到的结果,但找不到将实体作为Doctrine对象的解决方案。目前我有两个函数,一个返回数组,在那里我确实需要深度和查找,如果我需要对象,我使用默认的理论函数(例如,ParentID ),但我想要一个优雅的解决方案。另外,我认为我在将来会用到其他对象,例如:一个人的年龄(从生日开始计算)。

EN

回答 1

Stack Overflow用户

发布于 2016-05-11 16:53:42

这应该会让你得到你想要的(可能需要稍微修修补补):

代码语言:javascript
运行
复制
    $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();

编辑:不要紧。我只是注意到你需要一个对象,而不是一个数组。

您可能想要查看以下两个扩展之一:https://github.com/Atlantic18/DoctrineExtensions/blob/master/doc/tree.md

或者,作为另一种选择,使用所需的字段创建一个新的对象类,将其标记为Doctrine的readOnly并为其创建自定义查询(您可以阅读在Doctrine中使用虚拟表的相关内容)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26968809

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档