0

我有一个新的 Laravel 5.8 应用程序。我开始使用 Eloquent 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 tableIP table

public function ip()
{
    return $this->hasOne('App\Models\Ip');
}

完成后,我想检索登录表的第一条记录的 IP 地址:

Login::find(1)->data()->ip()->get();

但我得到这个错误:

Call to undefined method Illuminate\Database\Eloquent\Relations\HasOne::ip()

我在这里缺少什么,如何以正确的方式获取该登录的 IP?我需要一个belongsTo地方吗?

4

3 回答 3

5

第一个错误:错误的关系定义

Laravel 关系是双向的。在one-to-one关系上,您可以定义正向关系 ( HasOne) 和反向关系 ( BelongsTo)

直接关系应该是:

             HasOne                HasOne
[ Login ] <----------- [ Data ] <----------- [ IP ]

反比关系应该是:

           BelongsTo             BelongsTo
[ Login ] -----------> [ Data ] -----------> [ IP ]

有关如何定义它的详细信息,请参阅Eloquent:Relationships - 一对一文档。

请注意,除非您需要,否则您不需要为关系定义两个方向。就您而言,我认为您只需要定义belongsTo方向。

第二个错误:您正在调用关系方法,而不是关系本身

当你这样做时:

Login::find(1)->data()->ip()->get();

您正在调用data定义您的关系的方法,而不是相关模型。这在某些情况下很有用,但不适用于您的情况。

正确的是调用关系魔术属性:

Login::find(1)->data->ip;

请注意,我们不使用(),我们也不需要get()这里。Laravel 负责为我们加载它。

使用急切加载

Laravel Eloquent 有一个对关系的急切加载,这在某些情况下非常有用,因为它预先加载了您的关系,并减少了您执行的查询数量。

在您描述的情况下(加载单个Login模型),它不会提高性能,但也不会减慢速度。

当您加载许多模型时它很有用,因此它将您的数据库查询计数N+12.

假设您正在加载 100 个Login模型,如果没有预先加载,您将执行 1 次查询来获取您的Login模型,执行 100 次查询来获取您的Data模型,以及更多 100 次查询来获取您的Ip模型。

使用预加载,它只会执行 3 次查询,从而导致性能大幅提升。

于 2019-07-09T12:58:15.780 回答
2

使用您的数据库结构:

登录belongsTo数据

资料hasOne登入

数据belongsToIP

知识产权hasOne数据

修复你的方法后,你可以像这样使用你的关系

$login = Login::with(['data.ip'])->find(1);

于 2019-07-09T12:47:13.057 回答
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

于 2019-07-09T12:30:20.603 回答