【问题标题】:Retrieve related data (hasMany) in CakePHP 3在 CakePHP 3 中检索相关数据 (hasMany)
【发布时间】:2016-09-16 08:20:23
【问题描述】:
Events hasMany TicketTypes
TicketTypes belogsTo Events

我正在尝试检索具有相关票证类型的所有事件:

$query= $this->Events
    ->find()
    ->select(['id', 'name'])
    ->autoFields(false)
    ->contain(['TicketTypes' => function($q) { 
        return $q->select(['TicketTypes.id', 'TicketTypes.name']); }])
;

生成的 SQL 查询:

SELECT Events.id AS `Events__id`, Events.name AS `Events__name` FROM events Events

但我的预期是:

SELECT Events.id AS `Events__id`, Events.name AS `Events__name`, TicketTypes.id AS `TicketTypes__id`, TicketTypes.name AS `TicketTypes__name` FROM events Events LEFT JOIN ticket_types TicketTypes ON Events.id = (TicketTypes.event_id)

这是我的模型的配置方式:

class EventsTable extends Table
{
    public function initialize(array $config)
    {
        $this->displayField('name');

        $this->addAssociations([
            'hasMany'=> ['TicketTypes']
        ]);
    }
}

class TicketTypesTable extends Table
{
    public function initialize(array $config)
    {
        $this->displayField('name');

        $this->addAssociations([
            'belongsTo' => ['Events']
        ]); 
    }
}

这是我的查找查询的调试结果:

object(Cake\ORM\Query) {

    '(help)' => 'This is a Query object, to get the results execute or iterate it.',
    'sql' => 'SELECT Events.id AS `Events__id`, Events.name AS `Events__name` FROM events Events',
    'params' => [],
    'defaultTypes' => [
        'Events.id' => 'integer',
        'id' => 'integer',
        'Events.name' => 'string',
        'name' => 'string',
        'Events.datetime_start' => 'datetime',
        'datetime_start' => 'datetime',
        'Events.datetime_end' => 'datetime',
        'datetime_end' => 'datetime',
        'Events.created' => 'datetime',
        'created' => 'datetime',
        'Events.modified' => 'datetime',
        'modified' => 'datetime',
        'Events.slug' => 'string',
        'slug' => 'string',
        'TicketTypes.id' => 'integer',
        'TicketTypes.event_id' => 'integer',
        'event_id' => 'integer',
        'TicketTypes.name' => 'string',
        'TicketTypes.description' => 'text'
    ],
    'decorators' => (int) 0,
    'executed' => false,
    'hydrate' => true,
    'buffered' => true,
    'formatters' => (int) 0,
    'mapReducers' => (int) 0,
    'contain' => [
        'TicketTypes' => [
            'queryBuilder' => object(Closure) {

            }
        ]
    ],
    'matching' => [],
    'extraOptions' => [],
    'repository' => object(App\Model\Table\EventsTable) {

        'registryAlias' => 'Events',
        'table' => 'events',
        'alias' => 'Events',
        'entityClass' => 'App\Model\Entity\Event',
        'associations' => [
            (int) 0 => 'tickettypes'
        ],
        'behaviors' => [],
        'defaultConnection' => 'default',
        'connectionName' => 'default'

    }

}

这是调试的结果$query->all():

object(Cake\ORM\ResultSet) {

    'items' => [
        (int) 0 => object(App\Model\Entity\Event) {

            'id' => (int) 101,
            'name' => 'qwertyuiop',
            'ticket_types' => [],
            '[new]' => false,
            '[accessible]' => [
                '*' => true
            ],
            '[dirty]' => [],
            '[original]' => [],
            '[virtual]' => [],
            '[errors]' => [],
            '[repository]' => 'Events'

        },
    ...

正如您在这一行中看到的 'ticket_types' => [] 票证类型没有被查询返回。

如何检索TicketTypes 数据?

谢谢。

【问题讨论】:

  • 您的问题有点离题,因为您没有详细说明您的实际问题!熟悉 CakePHP 工作原理的人可能能够弄清楚您对什么感到困惑,但这不是 StackOverflow 的工作原理,问题应该清楚地说明问题,这样就没有人猜测您要问的是什么。话虽如此,使用contain 会导致ORM 加载关联的TicketTypes,所以这就是您必须做的,以及您已经在做的事情。如果有具体问题,请提及。
  • 您好 ndm,非常感谢您的 cmets。请记住,这是我的第一篇文章。我将编辑我的问题以使其更清楚。问候。

标签: cakephp associations cakephp-3.0 query-builder


【解决方案1】:

hasMany 关联正在单独的查询中检索

您对 CakePHP ORM 如何检索关联数据的假设不正确。

与在主查询中使用连接的 hasOne 和 belongsTo 关联不同,hasMany 和 belongsToMany 关联数据在单独的查询中检索,该查询使用从主查询中收集的外键值进行过滤查询,在您的情况下是 Events.id 列值。

查看其余的 SQL 日志,你应该会发现类似的查询

SELECT
    TicketTypes.id AS `TicketTypes__id`, ...
FROM
    ticket_types TicketTypes
WHERE
    TicketTypes.event_id IN (1,2,3, ...)

该查询的结果与主要结果拼接在一起,并在单个结果集中返回。

需要选择外键

第二个问题是您的容器select() 调用缺少外键列(TicketTypes.event_id),这是必需的,因为没有它,ORM 无法将结果拼接在一起,因此票证类型不会出现在结果中。

引用自文档:

当您限制从关联中获取的字段时,您 必须确保选择了外键列。未能 选择外键字段将导致关联数据不存在 在最终结果中。

另见

【讨论】:

  • 我已经调试了结果,但我期望的数据不存在。 object(Cake\ORM\Query) { '(help)' => 'This is a Query object, to get the results execute or iterate it.', 'sql' => 'SELECT Events.id AS Events__id, Events.name AS Events__name` FROM events Events',` ...
  • @DanielFuscoCiccariell book.cakephp.org/3.0/en/orm/…
  • 你介意看看我原来的问题。我添加了debug($query->all); 的输出。谢谢。
  • @dfc 您需要在容器select() 中包含外键(TicketTypes.event_id),否则结果无法拼接在一起,我忽略了这一点。通常这应该触发一个错误,不知道为什么它不再这样做(可能是一个错误,可能是一个故意的改变)。 book.cakephp.org/3.0/en/orm/…。稍后我会更新我的答案。
  • 现在我们开始说话了!非常感谢您的帮助和耐心。祝你有美好的一天!
猜你喜欢
  • 2016-04-10
  • 1970-01-01
  • 1970-01-01
  • 2023-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多