首页 文章

循环中的雄辩关系

提问于
浏览
2

我正在构建一个现有数据库(一个名为Epicor的ERP系统)的Laravel前端,以便在单独的(新)数据库中扩展该功能 . 目前,我正在尝试显示具有运送给客户状态的“设备”,并包含来自零件表的信息 . 数据库关系都存在,我可以使用SSMS获取所需的所有信息 - 所以我相信我在使用Eloquent时一定会出错 . 我有以下型号:

Equipment - 这是系统中的序列号,因此实际上是一个部件的实例:

<?php

class Equipment extends Model
{
    protected $table = 'ERP.SerialNo';
    public $timestamps = false;
    protected $primaryKey = 'SerialNumber';
    protected $keyType = 'string';

    protected $fillable = [
        'SerialNumber',
        'SNStatus',
        'PartNum',
        'TerritoryID',
        'JobNum',
        'PackNum',
        'PackLine',
        'RMANum',
        'CustNum',
        'SNStatus'
    ];

    public function Part()
    {
        return $this->belongsTo(Part::class,'PartNum','PartNum');
    }

    public function Customer()
    {
        return $this->belongsTo(Customer::class,'CustNum', 'CustNum');
    }
}

Part

class Part extends Model
{
    protected $table = 'ERP.Part';
    public $timestamps = false;
    protected $primaryKey = 'PartNum';
    protected $keyType = 'string';

    protected $fillable = [
        'PartNum',
        'SearchWord',
        'Innactive',
        'PartDescription',
        'ClassID',
        'CommodityCode',
        'NetWeight'
    ];

    public function ShipmentLine()
    {
        return $this->hasMany(Shipment::class, 'PartNum', 'PartNum');
    }

    public function Equipment()
    {
        return $this->hasMany(Equipment::class,'PartNum', 'PartNum');
    }
}

Customer Controller

public function show($CustID)
{
    $Customer = Customer::find($CustID);
    $Shipments = $Customer->Shipment->where('Voided', '0');
    $Equipments = $Customer->Equipment->where('SNStatus', 'SHIPPED');
    return view('Customer.show', compact('Equipments',     'Customer','Shipments', 'Parts'));
}

show.blade.php (under Customer)

<?php

@foreach($Equipments as $Equipment)
    <tr>
        <td>ClassID</td>
        <td><a href="{{ route('Part.show',$Equipment->PartNum)}}">{{$Equipment->PartNum}}</a></td>
        <td><a href="{{ route('Equipment.show',$Equipment->SerialNumber)}}">{{$Equipment->SerialNumber}}</a></td>
        <td>PartDescription is sometimes really really really long.....even longer than this!</td>
    </tr>
@endforeach

这一切都运行正常,我得到了所有具有运送给该客户状态的设备的清单 . 我现在要做的是,在设备列表中,包括Part表中的相关字段(ClassID和PartDescription) .

我尝试了一些东西,但觉得我抓着稻草,我的所有尝试都失败了 . 我设法在设备上显示show.blade.php部件信息,所以我相信模型设置好了 .

提前致谢,

理查德

2 回答

  • 2

    首先,Part模型内部的关系方法(以及Customer模型内部)必须以复数形式编写,因为您匹配多个实体:

    public function ShipmentLines()
    {
        return $this->hasMany(Shipment::class, 'PartNum', 'PartNum');
    }
    
    public function Equipments()
    {
        return $this->hasMany(Equipment::class,'PartNum', 'PartNum');
    }
    

    其次,您可以使用关系来加载控制器中的设备,而不是使用延迟加载:

    public function show($CustID)
    {
        $Customer = Customer::find($CustID);
        $Shipments = $Customer->ShipmentLines()
            ->where('Voided', '0')
            ->get();
        $Equipments = $Customer->Equipments()
            ->with('Part') // load the Part too in a single query
            ->where('SNStatus', 'SHIPPED')
            ->get();
        return view('Customer.show', compact('Equipments', 'Customer', 'Shipments'));
    }
    

    最后,在刀片模板中,您可以非常轻松地使用设备的一部分:

    @foreach ($Equipments as $Equipment)
            <tr>
                <td>{{$Equipment->Part->ClassID}}</td>
                <td><a href="{{ route('Part.show',$Equipment->PartNum)}}">{{$Equipment->PartNum}}</a></td>
                <td><a href="{{ route('Equipment.show',$Equipment->SerialNumber)}}">{{$Equipment->SerialNumber}}</a></td>
                <td>PartDescription is sometimes really really really long.....even longer than this!</td>
            </tr>
    @endforeach
    

    另外,我建议使用 @forelse 而不是 @foreach 来覆盖那些没有设备时的情况:

    @forelse ($Equipments as $Equipment)
            <tr>
                <td>{{$Equipment->Part->ClassID}}</td>
                <td><a href="{{ route('Part.show',$Equipment->PartNum)}}">{{$Equipment->PartNum}}</a></td>
                <td><a href="{{ route('Equipment.show',$Equipment->SerialNumber)}}">{{$Equipment->SerialNumber}}</a></td>
                <td>PartDescription is sometimes really really really long.....even longer than this!</td>
            </tr>
    @empty
            <tr>
                <td colspan="4">There is no existing equipment!</td>
            </tr>
    @endforelse
    
  • 1

    我想你要找的是with() .

    在我谈到这一点之前,你实际上遇到了比看起来更大的问题 . Matei Mihai实际上触及了这一点 .

    当你有像 $Customer->Equipment 这样的东西时,你're actually making use of Eloquent' s "dynamic properties" . 这意味着,在那里有一个神奇的 __get() ,它表示所需的属性是否已经通过 with()load() 急切加载 .

    所以当你做 $Customer->Equipment 时,它基本上是 $Customer->Equipment()->get() 的快捷方式 .

    接下来要考虑的是 get() 的结果是Eloquent\Collection,它是Support\Collections的子类 . 而Support \ Collections有自己的where()方法版本 .

    所有这些, $Customer->Equipment->where('SNStatus', 'SHIPPED') 不会导致运行如下所示的查询:

    SELECT * FROM Equipment WHERE customerID = ? AND SNStatus = 'SHIPPED'
    

    你正在做的是运行它:

    SELECT * FROM Equipment WHERE customerID = ?
    

    然后要求Collection类在 SNStatus='SHIPPED' 之后过滤生成的集合 . 这可能是一个巨大的性能损失,甚至可以最大化您的服务器RAM,具体取决于这些表的大小 . 我认为你真正想要的是:

    $Customer->Equipment()->where('SNStatus', 'SHIPPED')->get()

    通过调用实际的 Equipment() 方法而不是动态属性,你还没有为它执行查询做好准备,因为你还在为它添加条件 .

    (另外,作为旁注,你的命名惯例会伤害我的强迫症,方法应该总是“camelCased” . 只有类名的首字母大写 . )


    那么......回到你实际问过的问题,包括对 Model::where()Collection::where() 之间区别的理解,我们得到的是这样的:

    $resutls = $Customer->Equipment()->with(['Part'])->where('SNStatus', 'SHIPPED')->get();
    

    由于您要在Parts表中指定实际关注的几个字段,因此可以使用constrained eager-load

    $resutls = $Customer->Equipment()->with(['Part' => function (Illuminate\Database\Eloquent\Builder $query) {
        $query->select([
            'PartNum',  //Per Equipment::Part(), This needs to be there for the relation to be mated with its parent
            'ClassID',
            'PartDescription'
        ]);
        // Since PHP always handles objects by-reference, you don't actually need to return $query after having altered it here.
    }])->where('SNStatus', 'SHIPPED')->get();
    

    这将为您提供一个嵌套的 Part 对象,其中只包含您关注 Eloquent\Collection 结果中每个 Equipment 模型元素的字段 .

    至于如何在你的刀片文件中处理这些结果,我与Matei Mihai的不同之处在于,我认为答案非常好 .

相关问题