如何确定Eloquent关系(或执行传统连接)的范围

时间:2015-11-23 12:39:33

标签: php eloquent relational-database

我正在尝试构建一组Eloquent模型,这些模型代表现有的硬件设备数据库(两者都不能更改)。我知道如何在SQL中执行此操作,但我正在努力构建一个使用第三个表的模型关系,类似于关系/联结表,但与复合键一对一关系。

有三个实体(简化):

  1. 设备
  2. 会话
  3. device_user
  4. 用户可以同时在多个设备中,并具有与这些设备关联的会话日志。用户确实拥有唯一的ID,但从设备的角度来看,他们只有一个"用户编号"它只是短(3个字节),因此不能代表整个用户范围,因此它映射在device_user表中。 (它实际上比这更复杂,但出于这个问题的目的,我把它剥离了)

    设备表:

    d_id                PK
    [data fields...]
    

    device_user表:

    du_uid              User's actual ID
    du_device_id        FK to device.d_id
    du_number           000-999
    [metadata...]
    

    会话表:

    s_device_id         device.d_id
    s_user_number       000-999 (device_user.du_number)
    [data fields...]
    

    场景:我有一个会话,我想查找特定的device_user.d_uid。在SQL中我会做类似的事情:

    SELECT session.blah, du_uid
    FROM session
    INNER JOIN device_user ON du_device_id = s_device_id AND du_number = s_user_number
    

    所以我想这实际上只是一个复合键的关系。

    我在Eloquent中尝试的是这样的:

    class SessionLogModel {
    
        public function device(){
            return $this->belongsTo('MyModels\\DeviceModel', 's_device_id', 'd_id');
        }
    
        public function user(){
            return $this->belongsTo('MyModels\\DeviceUserModel', 's_user_number', 'du_number')
    
            // A) I tried:
            ->withDevice($this->s_device_id);
    
            // or B) I tried:
            ->withDevice($this->device());
    
        }
    
        // example usage
        public static function getRecentUser(DateTime $localTime, $deviceId){
            $u = null;
    
            // get the preceding session log
            $q = SessionLogModel::where('session_type', '=', 'S')
                ->where('session_device_id', '=', $deviceId)
                ->where('sesison_date', '<=', $localTime)
                ->orderBy('session_id', 'DESC')
                ->take(1)
                ->with('device')
                ->with('user');
            $s = $q->get()->first();
    
            $u = $s->user->du_uid; // use the unique user ID
            ...
        }
    }
    
    class DeviceUserModel {
        // A)
        public function scopeWithDevice($query, $device_id){
            return $query->where('du_device_id', '=', $device_id);
        }
        // OR B) I tried:
        public function scopeWithDevice($query, $device){
            return $query->where('du_device_id', '=', $device->d_id);
        }
    }
    

    我已经尝试了多种方法来限制匹配到两个范围内的列,或其他&#39;其中&#39;构造,但似乎总是有麻烦&#34;发送&#34;通过BelongsTo正确的价值。在检查DB :: getQueryLog时,设备ID以NULL形式出现。但是,如果我对属性中的值进行硬编码,我可以看到它&#34;工作&#34;。

    我已经对此进行了很多研究,但我发现很难找到类似的结构。

    我使用Laravel v4.2中的Eloquent独立使用(不在Laravel中)。

    上述基于范围的方法是否有效? 或者我应该看一个不同的方法?

1 个答案:

答案 0 :(得分:0)

我刚刚遇到了这个有趣的问题: 我厌倦了按如下方式在laravel中模拟你的桌子:

public function up(){
    Schema::create('session', function (Blueprint $table) {
        $table->increments('id');
        $table->integer('s_device_id');
        $table->string('s_user_number',20);
        $table->timestamps();
    });
    Schema::create('device', function (Blueprint $table) {
        $table->increments('d_id');
        $table->string('blah',20);
        $table->timestamps();
    });
    Schema::create('device_user', function (Blueprint $table) {
        $table->integer('du_device_id')->unsigned();
        $table->integer('du_uid')->unsigned();
        $table->string('du_number',20);
        $table->primary(['du_device_id', 'du_uid']);//important composite key
        $table->timestamps();
    });
}
//then do the relations on Medels:
//User Model
public function deviceUser(){
    return $this->hasOne(DeviceUser::class,'du_uid');
}
//Device Model
public function deviceUser(){
    return $this->hasOne(DeviceUser::class,'du_device_id','d_id');
}
//DeviceUser Model
public function device(){
    return $this->belongsTo(Device::class,'du_device_id','d_id');
}

public function user(){
    return $this->belongsTo(User::class,'du_uid');
}
//Session Model //[Not the Session Facade of Laravel]
public function device(){
    return $this->belongsTo(Device::class,'s_device_id');
}
//Now let us do the work in SessionController after filling your tables with demo data for e.g.
//all these relations are working fine!
    $device = Device::where('d_id',1)->first();
    $user = User::where('id',4)->first();

    //dd($user,$user->deviceUser,$device,$device->deviceUser);//here instance objects and their relations can be fetched easily

    $device_user = DeviceUser::where('du_device_id',1)->where('du_uid',4)->first();

    //dd($device_user,$device_user->device);
    //$session = Session::where('id',100)->first();//can get session by ID
    $session = Session::where('s_device_id',1)->where('s_user_number','000-999')->first();//get session by unique composite key which what you are after. It is similar to the sql Query that you built. Then you can easily fetch the relations as follows:
    dd($session,$session->device,$session->device->deviceUser);

希望这会有所帮助!