简体   繁体   English

Laravel eloquent - 与不同表的一对一关系

[英]Laravel eloquent - one to one relation with different table

I have three tables,我有三张桌子,

1. user (id, name)
2. state (id, stateName, code)
3. user_relations(id, user_id, state_id)

3 models, 3款车型,

1. User
2. State 
3. UserRelation

By logic, User has one UserRelation and UserRelation has one State从逻辑上来说, User有一个UserRelationUserRelation有一个State

I can get user state by我可以通过

User::first()->relation->state

What I want is call this by User::with('state')->first() .我想要的是通过User::with('state')->first()调用它。

If you would like to keep the current db schema like it is, you may use Laravel accessors如果你想保持当前的数据库模式,你可以使用Laravel 访问器

Accessors and mutators allow you to format Eloquent attribute values when you retrieve or set them on model instances.当您在模型实例上检索或设置 Eloquent 属性值时,访问器和修改器允许您格式化它们。

class User类用户

public function getStateAttribute($value) {
   return $this->relation->state;
}

Usage用法

User::findOrFail($id)->state;

Edit编辑

User Model用户模型

class User extends Authenticatable
{
    //...

    public function state() {
        return $this->relation()->with('state');
    }


    public function relation() {
        return $this->hasOne('App\UserRelation', 'user_id');
    }

}

UserRelation Model用户关系模型

class UserRelation extends Model
{
    protected $table = 'user_relations';


    public function state() {

        return $this->belongsTo('App\State'); // must be belongsTo instead of hasOne
    }

}

State Model状态模型

class State extends Model
{
    protected $table = 'states';
}

Controller控制器

App\User::with('state')->find(1);

{
  "id": 1,
  "name": "Test",
  "email": "test@test.com",
  "email_verified_at": "2020-02-13 00:00:00",
  "created_at": "2020-02-20 00:00:00",
  "updated_at": null,
  "state": {
    "id": 2,
    "state_id": 2,
    "user_id": 1,
    "state": {
      "id": 2,
      "stateName": "state 2",
      "code": "code 2"
    }
  }
}

If user can only have one state,如果用户只能有一种状态,

add a state_id in the user table and get rid of the third table user_relations在user表中添加一个state_id ,去掉第三个表user_relations

class User extends Model
{
    public function state()
    {
        return $this->hasOne('App\State');
    }
}

class State extends Model
{
    public function user()
    {
        return $this->belongsTo('App\User');
    }
}

In this way, you can通过这种方式,您可以

$state = User::find(1)->state;
$user = State::find(1)->user;

If you are doing one-to-one relationship you won't need a pivot table, in your case the user_relations table.如果您正在进行one-to-one关系,则不需要数据透视表,在您的情况下是user_relations表。 Pivot tables are used to express many-to-many relations.数据透视表用于表达many-to-many关系。

And for the solution you want.对于您想要的解决方案。 You will have to store the user_id in the state table.您必须将 user_id 存储在state表中。 so your state table should look like the following:所以你的状态表应该如下所示:

state (id, user_id, stateName, code)

Relations should be like:关系应该是这样的:

User model:用户模型:

public function state()
{
    return $this->hasOne('App\State');
}

State model:状态模型:

public function user()
{
    return $this->belongsTo('App\User');
}

First way:第一种方式:

You have to define state_id in users table for one to one relation.您必须在用户表中为一对一关系定义 state_id。

class User extends Model
{
    public function state()
    {
        return $this->hasOne('App\State');
    }
}

Or if you need same database structure, then或者,如果您需要相同的数据库结构,那么

Second Way:第二种方式:

Basically it's Many to Many relations between User and State .基本上它是User 和 State 之间的多对多关系

So better way is to define many to many relation function in Models of User and State considering UserRelation a middle(pivot) table.所以更好的方法是在考虑 UserRelation 一个中间(枢轴)表的用户和状态模型中定义多对多关系函数

class User extends Model
{
    public function states()
    {
        return $this->belongsToMany('App\State', 'user_relations');
    }
}

class State extends Model
{
    public function users()
    {
        return $this->belongsToMany('App\User', 'user_relations');
    }
}

and then to access states of user, you can call:然后访问用户的状态,您可以调用:

$user->states->first();

It's ok that you need one to one relation, you can call first() method to fetch first record od state.你需要一对一的关系没关系,你可以调用 first() 方法来获取第一条记录 od 状态。

Simillery to access user of state访问状态用户的相似之处

$state->users->first();

And if you need to access user_relations (one to one) only, you have to define methods in both user and state model:如果您只需要访问 user_relations(一对一),则必须在用户和状态模型中定义方法:

class User extends Model
{
    public function user_relation()
    {
        return $this->hasOne('App\UserRelation');
    }
}

class State extends Model
{
    public function user_relation()
    {
        return $this->hasOne('App\UserRelation');
    }
}

Since user and state are many to many, you can user belongsToMany function inside User model.由于用户和状态是多对多的,因此您可以在 User 模型中使用用户所属的多个函数。

public function states(){
    return $this->belongsToMany(State::class, 'user_relations', 'user_id', 'state_id');
}

You can get Eager Loading by retrieving both models related to the user like:您可以通过检索与用户相关的两个模型来获得Eager Loading ,例如:

$user = User::with('states')->first();

And now to retrieve states, you can loop through the states like:现在要检索状态,您可以循环遍历状态,例如:

foreach($user->states as $state){
    //Retrieved state model variable
    ....
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM