【问题标题】:Find Records Based on Distant belongsToMany > belongsTo Relationship根据 Distant belongsToMany > belongsTo 关系查找记录
【发布时间】:2018-07-13 04:34:01
【问题描述】:

我正在尝试显示一个产品页面,其中包含与特定资产类型匹配的资产列表。例如,对于产品“Acme Cream”,有两个资产: Nutrition-facts.pdf(文档类型)和 marketing-video.mp4(视频类型)。在产品页面上,我想显示与“视频”资产类型匹配的第一个资产(如果存在)。

我有以下关系:

Product 模型包含一个 DB 列 asset_id

class Product extends Model
{
    /**
     * The assets that belong to the product.
     */
    public function assets()
    {
        return $this->belongsToMany('App\Asset', 'product_asset');
    }
}

资产模型包括 DB 列 idasset_type_id

class Asset extends Model
{
    /**
     * Get the asset type that owns the asset.
     */
    public function asset_type()
    {
      return $this->belongsTo('App\AssetType');
    }

    /**
     * The products that belong to the asset.
     */
    public function products()
    {
      return $this->belongsToMany('App\Product', 'product_asset');
    }
}

AssetType 模型有两个 DB 列 idname

class AssetType extends Model
{
    /**
     * A asset type can have many assets
     */
    public function assets()
    {
      return $this->hasMany('App\Asset');
    }
}

如何通过按asset_type 过滤来有效地获取一个产品资源?请记住,我已经使用 Product::find(id) 查询了数据库并将该数据传递到视图中。这是否需要另一个查询(急切的加载可能会有所帮助)。我知道我可以使用foreach 循环,但在我看来,必须有更好、更“雄辩”的方式。

我正在尝试在产品详细信息页面(show.blade.php)上的这种情况下使用它(伪代码):

如果资产匹配类型“视频”,则首先在此 div 中显示。否则,不要显示 div。

看起来应该是简单的一行:

$product->assets()->asset_type()->where('name', '=', 'Video')->first()

到目前为止,我最接近的是这个丑陋的东西:

>>> $product = App\Product::with(['assets'])->find(1)
>>> $product->assets()->with(['asset_type' => function ($query) { $query->where('name', '=', 'Video'); }])->get()

但是,它仍然返回所有资产,除了那些不匹配的“asset_type”属性为空。添加->whereNotNull('asset_type')->get()只会导致无法找到asset_type列的错误。

另外,这听起来像是一个使用“Has Many Through”关系的机会,但我不清楚如何设置它。

非常感谢任何帮助!谢谢。

【问题讨论】:

  • 如果没有视频类型资产,那么不显示产品?
  • 属于多部作品吗?据我记得中间表是从相关模型名称的字母顺序派生出来的,包含 table1_id 和 table2_id 列。

标签: laravel eloquent


【解决方案1】:

您需要通过过滤预先加载您的关系:

假设您获取与产品信息的关系

$typeName = 'Video';

$product = App\Product::with([
            'asset' => function($query) use($typeName) {
                //Filter asset by type
                //See: https://laravel.com/docs/5.6/eloquent-relationships#constraining-eager-loads
                return $query->whereHas('asset_type',function($query) use($typeName) {
                    //Filter where the type's name equals..
                    //Each query is relative to its scope, in this case the 'type' relationship which refers to your 'type' Model
                    return $query->where('name','=',$typeName);
                });
            },
            //Nested relationship loading: https://laravel.com/docs/5.6/eloquent-relationships#querying-relations
            'assets.asset_type'
            ])
            ->find(1);


$assets = $product->assets;

假设您只获取资产

$productId = 1;
$typeName = 'Video';

//Returns a collection of eloquent models
$assets = Asset::whereHas('product',function($query) use ($productId) {
                //Filter product by its id
                return $query->where('id','=',$productId);
            })
            ->whereHas('asset_type',function($query) use ($typeName) {
                //Filter type by its name
                return $query->where('name','=',$typeName);
            })
            ->get();

【讨论】:

  • 非常感谢您!我真的绞尽脑汁。
猜你喜欢
  • 2018-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-02
  • 2014-01-07
相关资源
最近更新 更多