我有一个新的Laravel 5.8应用程序。我开始研究雄辩的ORM及其关系。
我马上遇到了一个问题。
我有下表。 (这只是一个示例,出于测试原因,不会成为实际的应用程序)
Login table:
--------------------------
| id | user | data_id |
--------------------------
| 1 | admin | 1 |
| 2 | admin | 2 |
| 3 | admin | 3 |
--------------------------
Data table:
--------------
| id | ip_id |
--------------
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
--------------
IP table:
----------------------
| id | ip |
----------------------
| 1 | 192.168.1.1 |
| 2 | 192.168.1.2 |
| 3 | 192.168.1.3 |
----------------------
我想要获得属于实际登录名的IP。
因此,我向具有hasOne
外键的Login table
添加了Data table
关系:
public function data()
{
return $this->hasOne('App\Models\Data');
}
然后,我向具有hasOne
外键的Data table
添加了IP table
关系:
public function ip()
{
return $this->hasOne('App\Models\Ip');
}
完成后,我想检索Login表的第一条记录的IP地址:
Login::find(1)->data()->ip()->get();
但是我得到这个错误:
Call to undefined method Illuminate\Database\Eloquent\Relations\HasOne::ip()
我在这里缺少什么?如何以正确的方式获取该登录名的IP?我在某个地方需要belongsTo
吗?
答案 0 :(得分:2)
使用您的数据库结构:
登录belongsTo
数据
数据hasOne
登录
数据belongsTo
IP
IP hasOne
数据
修正方法后,您可以使用这种关系
$login = Login::with(['data.ip'])->find(1);
答案 1 :(得分:2)
Laravel关系是双向的。在one-to-one
关系上,您可以定义直接关系(HasOne
)和反关系(BelongsTo
)
直接关系应为:
HasOne HasOne
[ Login ] <----------- [ Data ] <----------- [ IP ]
逆关系应该是:
BelongsTo BelongsTo
[ Login ] -----------> [ Data ] -----------> [ IP ]
有关定义的详细信息,请参见Eloquent: Relationships - One-to-One文档。
注意,除非需要,您无需为关系定义两个方向。就您而言,我认为您只需要定义belongsTo
方向。
当您这样做:
Login::find(1)->data()->ip()->get();
您正在调用方法data
来定义您的关系,而不是相关模型。在某些情况下,这很有用,但在您的情况下却没有。
正确的方法是调用关系魔术属性:
Login::find(1)->data->ip;
请注意,我们此处不使用()
,也不需要get()
。 Laravel负责为我们加载它。
Laravel Eloquent拥有一个Eager Loading的关系,在某些情况下非常有用,因为它可以预先加载您的关系,并减少查询量。
在您描述的情况下(加载单个Login
模型),它没有任何性能上的改进,但也没有降低速度。
在加载许多模型时很有用,因此可以将数据库查询次数从N+1
减少到2
。
想象一下,您正在加载100个Login
模型,而没有急于加载,您将执行1个查询以获取Login
模型,进行100个查询以获取Data
模型,以及另外100个查询以获取您的Ip
模型。
急于加载,它将仅执行3个查询,从而大大提高了性能。
答案 2 :(得分:1)
您可以尝试这样:
登录
public function data()
{
return $this->belongsTo('App\Models\Data', 'data_id');
}
数据
public function ip()
{
return $this->belongsTo('App\Models\Ip', 'ip_id');
}
$login = Login::with(['data.ip'])->find(1);
在data
内,您将拥有ip
像$login->data->ip
。