Laravel - 在插入之前检查数据库参数的有效方法

Muh*_*min 13 php mysql eloquent laravel-5

我填充了一种形式,其中生成的每个文本字段都基于数据库结果.我只是使用the命名每个文本字段id.现在填写表单时,我使用控制器来保存它.但是在插入数据库之前,我循环Request::input()检查每个项目是否存在这样的条目.我只是想知道是否有有效的方法来检查循环中的每个项目以将其插入到db中.这是我的代码

public function store(Request $request, $id, $inid)
{       
    $startOfDay = Carbon::now()->startOfDay();
    $endOfDay = Carbon::now()->endOfDay();

    $instruments = InstrumentReading::whereBetween('created_at', [$startOfDay, $endOfDay])
                                    ->where('iv_inid', '=', $inid)
                                    ->get();
    foreach ($request->input() as $k => $v) {
        $read = new InstrumentReading;
        $read->iv_inid = $inid;
        $read->iv_ipid = $k;
        $read->iv_usid = Auth::user()->id;
        $read->iv_reading = $v;
        $read->save();
    }
    if ($instruments->count() > 0) {            
        //to filter the iv_ipid...
        foreach($instruments as $instrument)
        {
            $instrument->iv_status = "VOID";
            $instrument->save();
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

sha*_*ddy 4

用有效的方法来说,您可以做的是简单地检查/仅从数据库中获取所有可能的行,并在循环中检查该行是否已插入。也只获取iv_ipid列,因为我们不需要表中的所有列来进行检查。仅选择我们需要的列会更快。您可以直接使用Fluent查询生成器Eloquent从数据库中提取数据,因为它大大提高了像这样的简单查询的性能。

public function store(Request $request, $id, $inid)
{
    // Search only records with submitted iv_ipid, iv_inid and created today
    $alreadyInserted = DB::table('instrument_readings')
                   ->whereBetween('created_at', [
                       Carbon::now()->startOfDay(), 
                       Carbon::now()->endOfDay()
                   ])
                   // Get only records with submitted iv_ipid
                   ->whereIn('iv_ipid', array_keys($request->input()))
                   // Get records with given iv_inid only
                   ->where('iv_inid', $inid)
                   // For our check we need only one column, 
                   // no need to select all of them, it will be fast
                   ->select('iv_ipid')
                   // Get the records from DB
                   ->lists('iv_ipid');

    foreach ($request->input() as $k => $v) {
        // Very simple check if iv_ipid is not in the array
        // it does not exists in the database
        if (!in_array($k, $alreadyInserted)) {
            $read = new InstrumentReading;
            $read->iv_inid = $inid;
            $read->iv_ipid = $k;
            $read->iv_usid = Auth::user()->id;
            $read->iv_reading = $v;
            $read->save();
        } else {
            //todo
        }
}
Run Code Online (Sandbox Code Playgroud)

这是迄今为止建议的最有效的方法,因为您一次只获取您感兴趣的记录,而不是今天的所有记录。另外,您只获取一列,即我们检查所需的一列。Eloquent通常会导致性能过热,因此在建议的代码中我直接使用Fluent,这会将这部分代码的执行速度提高约 20%。

原始代码中的错误是您每次都在循环中进行数据库调用。当您需要像检查这样简单的任务时,永远不要将数据库调用、查询等放在循环中。这是一种矫枉过正的行为。相反,在循环之前选择所有需要的数据,然后进行检查。

现在,这是为了您只需将新记录保存到数据库的情况。如果您想操作循环中的每条记录,假设您需要循环遍历每个提交的条目,获取模型或创建它(如果不存在),然后对此模型执行其他操作,那么最有效的方法是是这个:

public function store(Request $request, $id, $inid)
{
    foreach ($request->input() as $k => $v) {
       // Here you search for match with given attributes
       // If object in DB with this attributes exists
       // It will be returned, otherwise new one will be constructed
       // But yet not saved in DB
       $model = InstrumentReading::firstOrNew([
           'iv_inid' => $inid,
           'iv_ipid' => $k,
           'iv_usid' => Auth::user()->id
       ]);

       // Check if it is existing DB row or a new instance
       if (!$model->exists()) {
           // If it is a new one set $v and save
           $model->iv_reading = $v;
           $model->save();
       }

    // Do something with the model here
    .....   
}
Run Code Online (Sandbox Code Playgroud)

这样 Laravel 将检查数据库中是否已存在带有传递参数的模型,如果存在,它将为您返回它。如果它不存在,它将创建它的新实例,因此您可以设置$v并保存到数据库。因此,您可以对该模型执行其他任何操作,并且您可以确保在此之后它存在于数据库中。