首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

Symfony2/Doctrine 关联查询实战:YAML 映射与 DQL 多表连接全解析

     編輯:PHP 相關知識

场景介绍

在实际项目中,文章通常属于某个频道,并由某用户发布。本文以 MspArticle(文章)、MspChannel(频道)、MspUser(用户)三实体为例,演示如何通过 YAML 定义多对一/一对多关联,并使用 DQL 完成高效的联表查询。

实体映射定义

1. 文章实体

# src/Acme/MspadminBundle/Resources/config/doctrine/MspArticle.orm.yml
Acme\MspadminBundle\Entity\MspArticle:
    type: entity
    table: msp_article
    manyToOne:
        Channel:
            targetEntity: MspChannel
            inversedBy: Articles
            joinColumn:
                name: channel_id
                referencedColumnName: channel_id
        User:
            targetEntity: MspUser
            inversedBy: Userone
            joinColumn:
                name: user_id
                referencedColumnName: user_id
    # 此处省略 id、title、content 等字段映射

2. 频道实体

# MspChannel.orm.yml
Acme\MspadminBundle\Entity\MspChannel:
    type: entity
    table: msp_channel
    oneToMany:
        Articles:
            targetEntity: MspArticle
            mappedBy: Channel
    # 字段映射省略

3. 用户实体

# MspUser.orm.yml
Acme\MspadminBundle\Entity\MspUser:
    type: entity
    table: msp_user
    oneToMany:
        Userone:
            targetEntity: MspArticle
            mappedBy: User
    # 字段映射省略

DQL 联表查询

在 Repository 或 Controller 中:

<?php
// 获取 EntityManager
$em = $this->getDoctrine()->getManager();

// DQL:选择所需字段,使用别名简化
$dql = "SELECT a.id, a.checkStatus, a.title, a.releaseSysDate, a.visitTotal,
               u.userName, n.name
        FROM AcmeMspadminBundle:MspArticle a
        JOIN a.User u
        JOIN a.Channel n
        WHERE a.checkStatus = 0";

$query = $em->createQuery($dql);
$articles = $query->getResult(); // 返回数组,每项包含选中的标量值

// 若需获取对象图(含关联对象),可用:
// $dql = "SELECT a, u, n FROM AcmeMspadminBundle:MspArticle a JOIN a.User u JOIN a.Channel n WHERE a.checkStatus = 0";
// $articles = $query->getResult(); // 返回 MspArticle 对象集合,关联对象已预加载

进阶技巧

1. 使用 QueryBuilder 动态构建

$qb = $em->createQueryBuilder();
$qb->select('a.id, a.title, u.userName, n.name')
   ->from('AcmeMspadminBundle:MspArticle', 'a')
   ->innerJoin('a.User', 'u')
   ->innerJoin('a.Channel', 'n')
   ->where('a.checkStatus = :status')
   ->setParameter('status', 0);

$results = $qb->getQuery()->getResult();

2. 解决 N+1 问题(预加载)

若在模板中遍历 article.User.userName,默认会触发懒加载产生 N+1 查询。解决方案:

  • DQL 中显式 JOIN ... SELECT a, u, n(如上)。
  • 或在映射中配置 fetch: EAGER(慎用,可能导致过度加载)。

3. 结果集映射为自定义对象

$dql = "SELECT NEW Acme\MspadminBundle\DTO\ArticleListItem(a.id, a.title, u.userName, n.name)
        FROM AcmeMspadminBundle:MspArticle a JOIN a.User u JOIN a.Channel n
        WHERE a.checkStatus = 0";
// 需在 DTO 类定义对应构造函数

常见误区

误区正确做法
在 DQL 中写 SQL 表名必须使用实体类名和别名,如 AcmeBundle:Article a
JOIN 后未 SELECT 关联字段若只 SELECT a,关联对象不会被加载,模板访问时仍会触发懒加载
混用 YAML 与 Annotation 映射一个 Bundle 只能使用一种映射驱动,避免冲突

总结

Doctrine 的关联映射与 DQL 提供了强大的面向对象查询能力。掌握 ManyToOne/OneToMany 映射、JOIN ... SELECT 预加载、QueryBuilder 动态构建,能编写出既符合 OOP 又高效的数据访问代码。生产环境建议结合 Profiler 监控 SQL 条数,必要时引入二级缓存或读写分离。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved