渴望加载与Laravel 5

时间:2017-06-22 15:40:57

标签: php laravel eloquent

我目前正在开展一个项目,我必须使用一个构建糟糕的10年历史的数据库。 无论如何,我有两张桌子:一张用于产品,一张用于颜色。每个产品都由参考标识,每种颜色都由其自己的参考+产品标识。 例如,我有一个参考123的产品。该产品有3种颜色:123-01,123-02和123-03。这两个值分为两列:nocol(产品参考)和nopat(颜色参考)。 我不能为每种颜色都有一个唯一的ID,因为数据库每晚都被删除,因此ID总是在变化(我知道这很奇怪)。

目前我有三种型号:Product,Color和CartItem。我的颜色模型与产品模型具有一对一的关系。我的CartItem与我的Color模型有一对一的关系,定义如下:

public function color() {
  return $this->hasOne('App\Color', 'nocol', 'color_ref')->where('nopat', $this->product_ref);
}

这很好用,因为我可以用一个简单的$cartItem->color从CartItem中检索颜色。问题是它并不适用于急切的加载。当我尝试用这样的东西检索我的CartItems时:

CartItem::with('product', 'color')->get();

当我转储结果时,我最终得到一个空关系。

当索引是两个单独的列时,还有其他方法可以编写这种关系吗?

编辑07-10

根据要求,这是一个非常简单的数据库视图。正如我所说,我必须使用一个我无法修改的旧数据库。解决我的问题最简单的方法是在我的Color表中添加一个唯一的ID,但我无法做到这一点。

我的产品型号具有唯一ID pat_nopat。一个产品可以有多种颜色。我的颜色模型有两列col_nopatcol_nocolcol_nopat列引用了产品ID。这两列是Color模型的唯一ID。

我的OrderItem模型引用col_nopatcol_nocol的颜色,称为product_refcolor_ref

enter image description here

当我显示特定客户的订单历史记录时,我还会通过OrderItem模型显示有关颜色的一些信息。问题是它执行了太多查询,因为我无法找到一种方法来急切加载OrderItem和Color之间的关系。

编辑07-11

我尝试使用join子句而不是where子句来更改我的关系。急切的加载工作但结果是错误的。

如果我有两个具有相同颜色参考但具有不同产品参考的CartItem,我得到的结果是错误的。 让我们说我有两个这样的CartItem:

product_ref | color_ref
----------- | ---------
1234        | 01
5678        | 01

我使用where关系得到了正确的结果,除了我无法加载。

但是,两个行的连接关系返回1234-01,因为它为每个颜色引用获取第一个结果。 如果我查看调试栏中的查询,我会得到以下结果:

select * from `colors` inner join `cart_items` on `colors`.`col_nopat` = `cart_items`.`product_ref` where `colors`.`col_nocol` in ('01')
select * from `products` where `products`.`pat_nopat` in ('1234', '5678')

2 个答案:

答案 0 :(得分:2)

加入怎么样? (顺便说一下,它不是belongsTo关系而不是hasOne?)

public function color()
{
    return $this->belongsTo(Color::class, 'color_ref')
        ->join('order_items', 'colors.col_nopat', '=', 'order_items.product_ref');
}

编辑后,我发现此解决方案存在问题。在Eloquent中处理复合主键总是很困难,在这种情况下也是如此。

您可以作弊并急切加载所有匹配的颜色,然后按product_ref进行过滤。这样您就可以避免每个CartItem模型触发单独的查询。考虑一下:

// Product.php
public function colors()
{
    return $this->hasMany(Color::class, 'col_nopat', 'pat_nopat');
}

// ----

// CartItem.php
public function product()
{
    return $this->belongsTo(Product::class, 'product_ref');
}

public function getColorAttribute()
{
    return $this->product->colors
        ->where('col_nopat', $this->product_ref)
        ->first();
}

然后加载与CartItem::with('product.colors')的关系,然后您可以$item->color

替代:

// CartItem.php
public function color()
{
    return $this->hasMany(Color::class, 'col_nocol', 'color_ref')
        ->select('colors.*')
        ->join('items', function ($join) {
            $join->on('colors.col_nocol', '=', 'items.color_ref');
            $join->on('colors.col_nopat', '=', 'items.product_ref');
        });
}

public function getColorAttribute()
{
    return $this->getRelation('color')
        ->where('col_nopat', $this->product_ref)
        ->first();
}

(在此,您可以避免通过product关系。)

答案 1 :(得分:0)

将关系定义为:

public function color()
{
    return $this->hasOne('App\Color', 'nocol', 'color_ref');
}

然后使用eager loading constraint

CartItem::with(['product', 'color' => function ($q) use ($productRef) {
        $q->where('nopat', $productRef);
    }])
    ->get();