Laravel 4,凌乱的 Eloquent 连接查询

Posted

技术标签:

【中文标题】Laravel 4,凌乱的 Eloquent 连接查询【英文标题】:Laravel 4, messy Eloquent join query 【发布时间】:2014-07-23 12:48:49 【问题描述】:

我正在做一些杂乱无章的项目,其中 db 的结构是:

Object
id, title, description, url ... [and some more columns]

ObjectMeta
object_id, variable, value

所以让我们给你:

Object: 1, 'Cool Book', 'This cool book is just for you!', ...

Object Meta:
1, 'author_name', 'John Doe'
1, 'released', 2014
1, 'price', 23.22
1, 'url', 'http://amazon.com/coolbook'
1, 'genre', 3

所以我需要执行以下查询:

拉出所有类型为 3 的对象,然后按发布日期对这些对象进行排序。

$objs = static::Active()
->where('object', '=', $object)
->where('category','=',$category)
->whereIn('site_id', array(self::$site_id, 0))
->leftJoin('object_meta', function($join)

  $join->on('object.id','=', 'object_meta.content_id');
)
->where('object_meta.variable', 'genre')
->where('object_meta.value', 3);
->where('object_meta.variable', 'released');
->orderBy('object_meta.value', 'desc');
->groupBy('object.id')
->paginate(20);

即使有很多这样的书,这个查询也有 0 个结果。我知道这里的第二个 object_meta.variable 是有罪的。如何编写此查询以使其正常工作?

非常感谢您的帮助。

-- 编辑

我已经创建了解决方法,但它确实是非常糟糕的解决方法(有趣的是,我发誓上面的查询已经工作了一个月左右)。

$objs = static::Active()
->where('object', '=', $object)
->where('category','=',$category)
->whereIn('site_id', array(self::$site_id, 0))
->leftJoin('object_meta', function($join)

  $join->on('object.id','=', 'object_meta.content_id');
)
->where('object_meta.variable', 'genre')
->where('object_meta.value', 3);
->groupBy('object.id')
->get();

foreach($objs as $obj)

  $obj->id = $obj->object_id;
    $objs_meta = ObjectMeta::where('object_id',$obj->object_id)->get();
    foreach($objs_meta as $obj_meta)
    
      $variable = $obj_meta->var;
      $obj->$variable = $obj_meta->value;
    

$objs = $objs->sortBy(function($role)
  return $role->released;
);
$objs = Paginator::make($objs->toArray(), sizeof($objs), $limit);

【问题讨论】:

对于->where('object_meta.variable', 'released');,您正在尝试查找variable 等于genrereleased 的列?这可能是它返回 0 行的原因。 调试查询的第一件事是查看DB::getQueryLog() 日志,了解正在构建的查询。您也可以 ->toSql() 并使用即控制台直接针对数据库运行该查询。 是的,我知道这个问题。通过控制台对数据库运行时,查询不起作用。我真正想要的是以某种方式将“META.VAR”和“META.VALUE”信息注入我的“OBJECT”。所以我可以直接调用object.released、object.author、object.url,结果我会得到“META.VALUE”。 【参考方案1】:

你需要内连接 (join()) 而不是 leftJoin(),你需要两次:

$objs = static::Active()
 ->where('object', '=', $object)
 ->where('category','=',$category)
 ->whereIn('site_id', array(self::$site_id, 0))

 ->join('object_meta as genre', function ($join) 
   $join->on('object.id', '=', 'genre.content_id')
      ->where('genre.variable', '=', 'genre')
      ->where('genre.value', '=', 3);
 )
 ->join('object_meta as released', function ($join) 
   $join->on('object.id', '=', 'released.content_id')
      ->where('released.variable', '=', 'released');
 )

 ->orderBy('released.value', 'desc');
 ->select('object.*', 'released.value as released')

 ->distinct()
 // or group by, doesn't matter in your case
 // ->groupBy('object.id')

 ->paginate(20);

然后您的对象将具有附加属性released 并具有适当的值。


根据cmets:

如果你想动态添加连接,那么我建议如下范围:

public function scopeGenre($query, $value)

   $query->join('object_meta as genre', function ($join) use ($value) 
       $join->on('object.id', '=', 'genre.content_id')
          ->where('genre.variable', '=', 'genre')
          ->where('genre.value', '=', $value);
     );

然后:

$query->where(..)->genre(3)->...

【讨论】:

这就是我想要的! PS。有没有办法在 X 连接中包含 X 变量(基本上是每个 MetaObject),这样我就可以使用所有其他属性?用户可以定义“流派”、“发布”等变量。 你的意思是像那些加入的动态数量? 是的。基本上,书籍有大约 6 个元对象(流派、网址、价格等),而音乐或视频有更多元对象(大约 10 个)。我可以在需要时手动添加连接,但查询拉出所有 MetaObject 会很好。使用您的代码,我将能够使用genre.value 和released.value,但是对于url.value,我需要进行另一个连接。 请不要再介意了!在这个加入问题上工作了 3 个小时后,我无法正确思考。用简单的 foreach 和使用参数解决它 -> pastebin.com/Na7tgckT

以上是关于Laravel 4,凌乱的 Eloquent 连接查询的主要内容,如果未能解决你的问题,请参考以下文章

使用 Laravel 4 Eloquent 连接列上的列名“”无效?

Laravel - Eloquent 连接

Laravel 带计数的多重连接(不是 Eloquent)

如何使用 eloquent 在 laravel 中编写多个连接

Laravel - 使用 Eloquent 从连接关系模型中选择特定列

使用 eloquent laravel 获取连接表数据