【问题标题】:CakePHP matching associated data, not all values returnCakePHP 匹配关联数据,并非所有值都返回
【发布时间】:2020-03-06 13:15:50
【问题描述】:

我有事件和距离,模型如下所示:"

/* EventsTable.php */
class EventsTable extends Table
{
    public function initialize(array $config): void
    {
        ...
        $this->belongsToMany('Distances', [
            'foreignKey' => 'event_id',
            'targetForeignKey' => 'distance_id',
            'joinTable' => 'distances_events',
            'dependent' => true
        ]);

/*DistancesTable.php*/
class DistancesTable extends Table
{
    public function initialize(array $config): void
    {
        ...
        $this->belongsToMany('Events', [
            'foreignKey' => 'distance_id',
            'targetForeignKey' => 'event_id',
            'joinTable' => 'distances_events'
        ]);
    }

以下事件(和距离)

  • 赛事 1:25 公里、500 公里
  • 赛事 2:25 公里
  • 赛事3:100公里

我正在尝试选择在给定的最小和最大距离之间至少有一个距离的所有事件。所以我使用这个代码:

$mindistance = 50;
$maxdistance = 550;
$events = $this->Events
    ->find()
    ->contain(['Distances'])
    ->matching('Distances', function ($q) use ($maxdistance, $mindistance) {
      return $q->where(['Distances.title <=' => $maxdistance, 'Distances.title >=' => $mindistance]);
    });

返回我:

  • 赛事 1:500 公里
  • 赛事 3:100 公里

我缺少包含数据中的 25 公里距离。 如何应用此过滤器,但要保持事件的所有距离?

生成的 SQL:

SELECT 
  Events.id AS Events__id, 
  Events.user_id AS Events__user_id, 
  Events.title AS Events__title, 
  Events.slug AS Events__slug, 
  Events.type AS Events__type, 
  Events.description AS Events__description, 
  Events.datetime AS Events__datetime, 
  Events.country AS Events__country, 
  Events.province AS Events__province, 
  Events.city AS Events__city, 
  Events.street AS Events__street, 
  Events.housenumber AS Events__housenumber, 
  Events.zipcode AS Events__zipcode, 
  Events.lat AS Events__lat, 
  Events.lon AS Events__lon, 
  Events.price AS Events__price, 
  Events.active AS Events__active, 
  Events.created AS Events__created, 
  Events.modified AS Events__modified, 
  DistancesEvents.distance_id AS DistancesEvents__distance_id, 
  DistancesEvents.event_id AS DistancesEvents__event_id, 
  Distances.id AS Distances__id, 
  Distances.title AS Distances__title, 
  Distances.created AS Distances__created, 
  Distances.modified AS Distances__modified 
FROM 
  events Events 
  INNER JOIN distances_events DistancesEvents ON Events.id = (DistancesEvents.event_id) 
  INNER JOIN distances Distances ON (
    Distances.title <= '550' 
    AND Distances.title >= '50' 
    AND Distances.id = (DistancesEvents.distance_id)
  )


SELECT 
  DistancesEvents.distance_id AS Distances_CJoin__distance_id, 
  DistancesEvents.event_id AS Distances_CJoin__event_id, 
  Distances.id AS Distances__id, 
  Distances.title AS Distances__title, 
  Distances.created AS Distances__created, 
  Distances.modified AS Distances__modified 
FROM 
  distances Distances 
  INNER JOIN distances_events DistancesEvents ON Distances.id = (DistancesEvents.distance_id) 
WHERE 
  DistancesEvents.event_id in (8, 10)

【问题讨论】:

  • 你的 CakePHP 的确切版本是什么?这真的是您查询的所有代码吗?您如何测试是否真的是匹配会影响您的结果?生成的用于获取关联记录的 SQL 是什么样的?
  • @ndm,我使用的是 3.8.10;我已将生成的 SQL 添加到问题中。
  • 将数字与明显的字符串列进行比较是令人担忧的,但它不应影响关联查询或其结果的合并。我无法重现您的问题,使用 3.8.10 匹配并包含使用您的配置在这里工作得很好。
  • @ndm,是的,它有效。发现表字段Distances.titlevarchar 而不是int

标签: php cakephp cakephp-3.x


【解决方案1】:

在 EventsTable 中创建两个与距离的关系,第一个用于匹配,第二个用于所有距离:

/* EventsTable.php */
class EventsTable extends Table
{
    public function initialize(array $config): void
    {
        ...
        $this->belongsToMany('MatchedDistances', [
            'foreignKey' => 'event_id',
            'targetForeignKey' => 'distance_id',
            'joinTable' => 'distances_events',
            'dependent' => true
        ]);
        $this->belongsToMany('Distances', [
            'foreignKey' => 'event_id',
            'targetForeignKey' => 'distance_id',
            'joinTable' => 'distances_events',
            'dependent' => true
        ]);

然后:

$mindistance = 50;
$maxdistance = 550;
$events = $this->Events
    ->find()
    ->contain(['MatchedDistances'])
    ->contain(['Distances'])
    ->matching('MatchedDistances', function ($q) use ($maxdistance, $mindistance) {
      return $q->where(['MatchedDistances.title <=' => $maxdistance, 'MatchedDistances.title >=' => $mindistance]);
    });

【讨论】:

  • 感谢您的付出。我的代码确实有效。这是一个数据库表字段 (Distances.title) 是一个 varchar 而不是 int
猜你喜欢
  • 1970-01-01
  • 2015-11-29
  • 2011-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多