在 Laravel Eloquent 模型中使用特殊的联合函数
Posted
技术标签:
【中文标题】在 Laravel Eloquent 模型中使用特殊的联合函数【英文标题】:Using special union functions inside Laravel Eloquent model 【发布时间】:2019-03-29 19:57:54 【问题描述】:我已经开始使用 Laravel 开发一个网站,我几乎可以通过我在这里找到的官方文档和答案找到所有内容。然而,有一件事——即使我找到了一种方法——我有一种感觉,可以用另一种比我现在做的更优化的方式来完成。让我解释一下。
对于我的网站,我有一个名为“球员”的表格,其中包含从足球比赛中提取的一些球员的数据。假设结构是这样的:
ID(整数,主键,A_I)
GameID (int, unique) //游戏使用什么
玩家姓名
数据(基本上很多不同的列)
由于我的网站的目的是允许用户对游戏内容进行修改,我还有另一个表,我称之为“userplayers”,用于对原始表中存在的玩家进行修改,或添加新的。该结构类似于“玩家”表,但只添加了一个名为 userID 的列,用于标识哪个修改属于哪个用户。
ID(整数,主键,A_I)
GameID(整数,与用户 ID 一起唯一)
玩家姓名
数据(基本上很多不同的列)
UserID(整数,与 GameID 一起唯一)
如果我在 userplayers 表上添加一个条目,如果该条目与玩家表上的任何条目具有相同的 GameID(并且创建它的用户已登录),那么在运行时它会覆盖玩家表条目.如果新条目的 GameID 不存在于原始玩家表中,那么它只是被附加到它上面。
如果用户没有登录,那么我只返回玩家表。
通过使用 eloquent laravel 模型,我可以轻松地检索用户未登录时的玩家表。但是,我无法找到一种有效的方法来返回整个数据库 + 仅使用核心 eloquent 的用户创建的内容模型函数。
过去(没有 Laravel)我使用这个数据库查询:
SELECT * FROM (SELECT *, NULL FROM players WHERE NOT EXISTS (SELECT * FROM userplayers WHERE players.gameid=userplayers.gameid AND userId=$userId) UNION (SELECT * FROM userplayers WHERE userId=$userId)) AS pl;
而我“发现”在 Laravel 中执行此类操作的方法是在 Players 模型中添加一个本地范围,如下所示:
public function scopeIncludeCustom($query, $user)
return \DB::select('SELECT * FROM (SELECT *, NULL FROM players WHERE NOT EXISTS (SELECT * FROM userplayers WHERE userplayers.gameid=players.gameid AND userId='.$user.') UNION (SELECT * FROM userplayers WHERE userId='.$user.')) AS players_full);
但是您可以理解,这并没有按照作用域的预期返回 $query,而只是返回了一个 php 数组,我认为这不是正确的方法。例如,当我只搜索玩家表时(不使用用户创建的内容),返回结果所需的时间比返回自定义内容的结果要短得多。
非常感谢任何想法。
【问题讨论】:
已经定义了Player
和UserPlayer
模型?你熟悉 Eloquent 关系和whereHas()
吗?
@JonasStaudenmeir 是的,我已经定义了这两个模型,但我似乎不明白如何通过whereHas()
等关系来表示上述 mysql 语法
你可以在 Eloquent 中使用 UNION
查询,但结果都是 Player
模型的实例:如果你想要 Player
和 UserPlayer
实例,你必须执行单独的查询。
【参考方案1】:
所以,在研究了我的问题和可能的解决方案几天后,我想出了这个解决方案。
那么,让我们一步一步来吧。
我有一个“Player”模型,它从“players”表中获取数据。
我还有一个“Userplayer”模型,它从“userplayers”表中获取数据。
我必须在这两个模型之间建立关系。 “players”表中的条目可能在“userplayers”表中有许多与之相关的条目。所以,在 Player 模型中我添加了这个:
public function userplayers()
return $this->hasMany('App\Userplayer', 'gameid', 'gameid');
在 Userplayer 模型中,我添加了这个:
public function player()
return $this->belongsTo('App\Player', 'gameid', 'gameid');
请求数据时,第一步是从“players”表中删除与“userplayers”表,该表还有一个限制,即该表每一行的“userId”必须是特定的。
这是在我的 SearchPlayerController 中执行此操作的代码:
$orig_players = \App\Player::whereDoesntHave('userplayers', function ($query) use($user)
$query->where('userId', $user);
)->get();
同时,我需要从“userplayers”表中获取我想要的“userid”的每一行
$userplayers = \App\Userplayer::where([
['pesid', $search]
])->get();
现在,我只是合并 2 个结果(我不能使用 UNION,因为我从“players”表中获取的数据少了一列)。
$players = $orig_players->merge($userplayers)
->sortBy('registeredName')
->take($limit);
一切都运行良好,而且比以前快很多!
【讨论】:
以上是关于在 Laravel Eloquent 模型中使用特殊的联合函数的主要内容,如果未能解决你的问题,请参考以下文章
Laravel 5 - 使用 Mockery 模拟 Eloquent 模型
在 Laravel 中扩展 Eloquent 模型(使用不同的表)
Laravel/Eloquent 建议覆盖 trait 属性?
如何在 Eloquent 模型中使用 Laravel Livewire?