首页 > 解决方案 > 如何使用 Eloquent 在两个表之外的不同数据库中查找相关值?

问题描述

我正在开发一个扩展现有 ERP 系统的系统,因此正在访问两个数据库(都在同一个 MS SQL Server 上)。我正在尝试通过“EquipmentType”模型中的“EquipmentInstance”模型(这两个在新数据库中)访问“Equipment”模型(这是 ERP 数据库中的一个表)上的项目。根据此图,它们是相关的:

描述关系的 ER 图

三种型号如下:

设备类型

namespace App;

use Illuminate\Database\Eloquent\Model;

class EquipmentType extends Model
{
    protected $table = 'dbo.EquipmentType';
    protected $connection = 'sqlsrv';
    protected $primaryKey = 'EquipmentTypeID';
    protected $fillable = [
        'TypeName',
        'ProductManager'
        ];

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

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

设备实例

namespace App;

use Illuminate\Database\Eloquent\Model;

class EquipmentInstance extends Model
{
    protected $table = 'dbo.EquipmentInstance';
    protected $primaryKey = 'EquipmentID';
    protected $keyType = 'string';
    protected $connection = 'sqlsrv';
    protected $fillable = [
        'EquipmentID',
        'EquipmentTypeID',
        'PartNum'
    ];

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

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

    public function EquipmentType()
    {
        return $this->belongsTo(EquipmentType::class); /*,'EquipmentTypeID', 'EquipmentTypeID'*/
    }


/*    public function Attribute()
    {
        return $this->belongsTo(Equipment::class,'SerialNumber', 'JobNum');
    }

    public function TechNote()
    {
        return $this->belongsTo(Equipment::class,'SerialNumber', 'JobNum');
    }*/

}

设备

namespace App;

use Illuminate\Database\Eloquent\Model;

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


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

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

    public function Equipment()
    {
        return $this->belongsTo(Equipment::class,'SerialNumber', 'JobNum');
    }

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

在 EquipmentType 控制器上,我试图通过 EquipmentInstance 获取所有设备,因此对于每个 EquipmentInstance,我可以显示所有设备。

设备类型控制器

public function show(EquipmentType $EquipmentType)
{
    $EquipmentInstance = $EquipmentType->EquipmentInstance()
        ->get();

    $Equipments = $EquipmentType->EquipmentInstance()->Equipment()
        ->get();

    return view('EquipmentType.show', compact('EquipmentType', 'EquipmentInstance', 'Equipments'));

}

我得到的错误信息是

"BadMethodCallException
Call to undefined method Illuminate\Database\Eloquent\Relations\HasMany::Equipment()"

我认为问题在于(我的理解是不稳定的)Eloquent 试图编写一个查询来访问两个数据库,但这是失败的。但是我不确定如何进行。

任何帮助都会受到极大的欢迎。

理查德

更新

我已经实施了 gbalduzzi 在他的回答中提出的建议,几乎奏效了,我确信问题出在我的刀片实现上。我嵌套了两个forloops:

@foreach($EquipmentType->EquipmentInstance as $EquipmentInstance)
    @foreach($Equipments as $Equipment)
        <tr>
        <td>{{$EquipmentInstance->PartNum}} - {{$EquipmentInstance->Part->PartDescription}}</td>
         <td><a href="">{{$Equipment->SerialNumber}}</a></td>
         <td>{{$Equipment->SNStatus}}</td>
         <td>{{--{{$Equipment->Customer->LegalName}}--}}</td>
         </tr>
    @endforeach
@endforeach 

仅显示第一个 EquipmentInstance 的序列号(来自 Equipment 模型),并为所有 EquipmentInstanced 重复它们。

更新 2

我已经证明问题出在建议的答案中的 first() 上,就好像我将其更改为 last() 一样,结果会按照您的预期发生变化(请参阅更新 1)。所以我现在的问题是:

是否有 first()、last() 的等价物,即 all() 或every()?

标签: laraveleloquent

解决方案


问题不在于您的数据库配置,而在于您调用关系的方式。代替:

$Equipments = $EquipmentType->EquipmentInstance()->Equipment()
    ->get();

利用:

$Equipments = $EquipmentType->EquipmentInstance->first()->Equipment()
    ->get();

长答案

在 Eloquent 中,您可以通过两种方式使用关系:

  • 作为一个魔法场(即$EquipmentType->EquipmentInstance)。在这种情况下,您会得到模型的一个实例EquipmentInstance(另外,如果您已经查询过它,它会直接返回值而不执行新查询)

  • 作为一个雄辩的查询(即$EquipmentType->EquipmentInstance())。使用它作为一个函数,你得到的不是模型而是一个RelationShip实例,这基本上是一个 eloquent 查询,可以与其他 eloquent 方法链接,例如where, orderBy, ecc

所以,如果你调用$EquipmentType->EquipmentInstance()->Equipment()它会抛出一个错误,因为 eloquent 查询没有关系Equipment()

另一方面,$EquipmentType->EquipmentInstance->Equipment之所以有效,是因为它调用了具有正确定义Equipment的关系的实际模型实例。Equipment


推荐阅读