Laravel使用模型关联时Blade foreach如何避免输出重复记录
问题原因
下拉选项重复的核心原因是直接遍历全量Stock库存记录渲染地点选项:同一存储地点如果存放多种物资,会对应多条Stock记录,直接循环就会重复输出同一地点的选项。
解决方案
方案1(推荐:控制器层查询去重,性能最优)
不需要把全量Stock传给视图用来渲染地点下拉,直接查询存在对应库存记录的不重复地点即可,修改控制器transfer方法:
public function transfer() { $assets = Asset::all(); // 仅查询有库存关联的地点,自动去重 $places = Place::whereHas('stocks')->get(); $quantities = AssetQuantity::all(); $services = Service::all(); $stocks = Stock::all(); return view('stock.transfer', compact('assets','places','quantities','services','stocks')); }
对应修改Blade模板的下拉遍历逻辑,直接遍历去重后的$places集合:
<div class="mb-3"> <label for="place_name" class="block mb-2 mt-2 text-sm font-medium text-gray-900 dark:text-gray-400"> Select a Place </label> <select id="place_name" name="selectPlace" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 cursor-pointer"> <option selected value="">Choose a Place</option> @foreach($places as $place) <option value="{{ $place->id }}">{{ $place->name }}</option> @endforeach </select> @error('selectPlace') <p class="input_validate">{{ $message }}</p> @enderror </div>
方案2(临时兼容:集合去重,不调整原有查询逻辑)
如果暂时不想调整控制器查询逻辑,可以在Blade遍历前对Stock关联的地点做去重,调用Laravel集合的unique()方法实现:
<div class="mb-3"> <label for="place_name" class="block mb-2 mt-2 text-sm font-medium text-gray-900 dark:text-gray-400"> Select a Place </label> <select id="place_name" name="selectPlace" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 cursor-pointer"> <option selected value="">Choose a Place</option> @foreach($stocks->pluck('places')->unique('id') as $place) <option value="{{ $place->id }}">{{ $place->name }}</option> @endforeach </select> @error('selectPlace') <p class="input_validate">{{ $message }}</p> @enderror </div>
注意:该方案会先加载所有Stock关联的Place模型再在内存中去重,库存数据量大时性能劣于方案1,优先选择方案1实现。
规范优化建议
现有模型关联命名不符合Laravel官方约定:belongsTo类型关联默认使用单数命名,建议将Stock模型中的places()方法改名为place(),避免后续调用关联时出现参数匹配问题:
class Stock extends Model { use HasFactory; protected $fillable = ['current_stock', 'asset_id', 'place_id', 'quantity_id']; public function assets() { return $this->belongsTo(Asset::class, 'asset_id'); } // 调整为单数命名,符合框架约定 public function place() { return $this->belongsTo(Place::class, 'place_id'); } public function quantity() { return $this->belongsTo(AssetQuantity::class, 'quantity_id'); } }
调整后调用关联直接使用$stock->place->id、$stock->place->name即可,无需使用复数形式。
内容的提问来源于stack exchange,提问作者Mohamed Zaki
相关产品推荐
相关产品推荐

