将涉及连接 table 的查询从 CakePHP 1.3 转换为 3
Translating query involving join table from CakePHP 1.3 to 3
我正在将应用程序从 Cake 1.3 迁移到 3.0。我的数据库有团队和人员(teams_people 通过 belongsToMany 关系连接他们)和部门(团队属于部门)。 teams_people table 有额外的信息,比如这个人在球队中的角色(队长,球员),球衣号码,位置,诸如此类。在下面的示例中,我正在尝试读取一个人所在的公开组中的团队列表,包括他们的位置等。
$teams = $this->Teams->find()
->select(['teams_people.*'])
->autoFields(true)
->contain(['Divisions'])
->leftJoin(
['teams_people'],
['teams_people.team_id = Teams.id']
)
->where([
'Divisions.is_open' => true,
'teams_people.person_id' => $id,
]);
这是我能找到的 Cake 1.3 查询最直接的翻译,但它不会工作,因为 "teams_people.*" 通配符是 1.3 的一部分。 (这在 中进行了讨论。)如果我将 teams_people 列的整个列表放在那里,它工作正常,但在我稍后添加更多列并且不是 DRY 的情况下这是脆弱的。 (目前,为了让它工作,我有一个辅助函数来查看模式并构建所有列的列表。)我对新的 ORM 还是很陌生,我想学习 "right" 现在做事的方式,以便我需要转换的许多查询可以在第一时间以最佳方式完成,而不是让杂乱无章地根深蒂固。
我不需要有关人员的信息(姓名等),因为 Auth 组件已经加载了这些信息。这就是为什么我没有在这里的任何地方直接让人们 table 参与进来(删除它可以保存查询),这反过来又是为什么我需要指定 teams_people table 的连接。仅靠 autoFields 不足以从手动连接的 table 中提取字段,因此我需要 select 来指定这些字段。
我觉得会有一些很好的方法来做到这一点,也许通过 People table 对象但使用 "matching" 函数或其他一些方法来查询人们 table 从未真正发生过? "Cakiest" 处理这种情况的方法是什么?
在您的情况下,匹配似乎是可行的方法,您的 table 已正确关联,因此实际上不需要使用自定义联接和其他东西。
这是一个基于您给定查询的基本示例:
$teams = $this->Teams
->find()
->contain(['Divisions'])
->matching('People', function(\Cake\ORM\Query $query) use ($id) {
return $query
->where([
'People.id' => $id
]);
}))
->where([
'Divisions.is_open' => true
]);
ORM 将为 people
和 teams_people
table 创建适当的内部联接,并使用它们来过滤人员 $id
被分配到的团队。这一切都是通过单个查询中的内部连接完成的,看起来像
SELECT
Teams.id AS `Teams__id`,
...,
People.id AS `People__id`,
...,
TeamsPeople.id AS `TeamsPeople__id`,
TeamsPeople.team_id AS `TeamsPeople__team_id`,
TeamsPeople.person_id AS `TeamsPeople__person_id`,
...,
Divisions.id AS `Divisions__id`,
...
FROM
teams Teams
INNER JOIN
people People
ON People.id = 1
INNER JOIN
teams_people TeamsPeople
ON (
Teams.id = (
TeamsPeople.team_id
)
AND People.id = (
TeamsPeople.person_id
)
)
INNER JOIN
divisions Divisions
ON Divisions.id = (
Teams.division_id
)
WHERE
Divisions.is_open = 1
来自联接 table 的数据将在特殊的 _matchingData
属性 中可用,它将在 TeamsPeople
键
中保存一个实体
$teamEntity->_matchingData['TeamsPeople']
另见 Cookbook > Database Access & ORM > Filtering by Associated Data
我正在将应用程序从 Cake 1.3 迁移到 3.0。我的数据库有团队和人员(teams_people 通过 belongsToMany 关系连接他们)和部门(团队属于部门)。 teams_people table 有额外的信息,比如这个人在球队中的角色(队长,球员),球衣号码,位置,诸如此类。在下面的示例中,我正在尝试读取一个人所在的公开组中的团队列表,包括他们的位置等。
$teams = $this->Teams->find()
->select(['teams_people.*'])
->autoFields(true)
->contain(['Divisions'])
->leftJoin(
['teams_people'],
['teams_people.team_id = Teams.id']
)
->where([
'Divisions.is_open' => true,
'teams_people.person_id' => $id,
]);
这是我能找到的 Cake 1.3 查询最直接的翻译,但它不会工作,因为 "teams_people.*" 通配符是 1.3 的一部分。 (这在
我不需要有关人员的信息(姓名等),因为 Auth 组件已经加载了这些信息。这就是为什么我没有在这里的任何地方直接让人们 table 参与进来(删除它可以保存查询),这反过来又是为什么我需要指定 teams_people table 的连接。仅靠 autoFields 不足以从手动连接的 table 中提取字段,因此我需要 select 来指定这些字段。
我觉得会有一些很好的方法来做到这一点,也许通过 People table 对象但使用 "matching" 函数或其他一些方法来查询人们 table 从未真正发生过? "Cakiest" 处理这种情况的方法是什么?
在您的情况下,匹配似乎是可行的方法,您的 table 已正确关联,因此实际上不需要使用自定义联接和其他东西。
这是一个基于您给定查询的基本示例:
$teams = $this->Teams
->find()
->contain(['Divisions'])
->matching('People', function(\Cake\ORM\Query $query) use ($id) {
return $query
->where([
'People.id' => $id
]);
}))
->where([
'Divisions.is_open' => true
]);
ORM 将为 people
和 teams_people
table 创建适当的内部联接,并使用它们来过滤人员 $id
被分配到的团队。这一切都是通过单个查询中的内部连接完成的,看起来像
SELECT
Teams.id AS `Teams__id`,
...,
People.id AS `People__id`,
...,
TeamsPeople.id AS `TeamsPeople__id`,
TeamsPeople.team_id AS `TeamsPeople__team_id`,
TeamsPeople.person_id AS `TeamsPeople__person_id`,
...,
Divisions.id AS `Divisions__id`,
...
FROM
teams Teams
INNER JOIN
people People
ON People.id = 1
INNER JOIN
teams_people TeamsPeople
ON (
Teams.id = (
TeamsPeople.team_id
)
AND People.id = (
TeamsPeople.person_id
)
)
INNER JOIN
divisions Divisions
ON Divisions.id = (
Teams.division_id
)
WHERE
Divisions.is_open = 1
来自联接 table 的数据将在特殊的 _matchingData
属性 中可用,它将在 TeamsPeople
键
$teamEntity->_matchingData['TeamsPeople']
另见 Cookbook > Database Access & ORM > Filtering by Associated Data