Laravel избегать дублирования записей в дочерней таблице - PullRequest
2 голосов
/ 07 мая 2020

У меня есть продукт, который имеет много штрих-кодов, когда я нахожусь на странице редактирования продукта и добавляю / удаляю / редактирую штрих-коды продукта, он снова сохраняет штрих-коды (PS: я знаю, откуда возникла проблема, но не уверен о решении для этого)

Logi c

Итак, вот что я ожидаю, когда я нахожусь на странице редактирования продукта:

  1. Если текущий штрих-коды изменились, просто обновите их
  2. если какой-либо из текущих штрих-кодов удален, удалите их из базы данных
  3. если какой-либо новый штрих-код добавлен в список, добавьте его в базу данных

В основном это sync() функциональность, которую я ищу, но, основываясь на моих модельных отношениях, я думаю, что использование sync() не является вариантом.

Код

Product model

public function barcodes()
{
    return $this->hasMany(Barcode::class, 'product_id', 'id');
}

barcode model

protected $fillable = [
    'product_id', 'serial_number',
];

public function product()
{
    return $this->belongsTo(Product::class);
}

Controller (update function)

public function update(Request $request, $id)
{
    $product = Product::find($id);
    $product->name = $request->input('name');
    if($product->save())
    {
        if(!empty($request->input('barcodes')))
        {
            foreach($request->input('barcodes') as $bb)
            {
                if(!empty($bb['serial_number'])){ // make sure no empty value saves
                    $barcode = new Barcode;
                    $barcode->product_id = $product->id;
                    $barcode->serial_number = $bb['serial_number'];
                    $barcode->save();
                }
            }
        }
    }
}

Как я уже упоминал выше I am aware where the issue comes from, but not sure about the solution for it и проблема повторяющиеся данные сохранения - это то, что я использую $barcode = new Barcode;.

Extra

Для ясности, это то, что мои данные lo хорошо, когда я отправляю запрос на обновление в серверную часть

one

Вопрос

Что мне следует изменить в моем коде, чтобы достичь мое желание logi c?

Ответы [ 2 ]

2 голосов
/ 07 мая 2020

Вот как я создаю функцию syn c для отношений «один-ко-многим»:

public function update(Request $request, $id)
{
    $product = Product::find($id);
    $product->name = $request->input('name');
    if($product->save())
    {
        if(!empty($request->input('barcodes')))
        {
            $barcodeSync = []; // We will use this to save all the barcode id's that exist in the database.
            foreach($request->input('barcodes') as $bb)
            {
                if(!empty($bb['serial_number'])){
                    $barcode = $product->barcodes()->updateOrCreate(
                        ['id' => $bb['id'] ?? 0],
                        ['serial_number' => $bb['serial_number']]
                    ); // This will create a new barcode for the product if that barcode doesn't exist yet or update the existing barcode using it's id.
                    array_push($barcodeSync, $barcode->id); // This will add the id to the array of existing barcodes for this product.
                }
            }
            $product->barcodes()->whereNotIn('id', $barcodeSync)->delete(); //Deletes all barcodes for this product that were not in the request.
        }
    }
}

Это должно оправдать ваши 3 ожидания.

  1. это будет обновите любой штрих-код, который соответствует 'id' и 'product_id'. (обратите внимание, что laravel фактически не обновляет модель, если 'serial_number не изменяется).

  2. Он сохраняет все созданные или обновленные штрих-коды для продукта в $barcodeSync массив, чтобы позже вы могли удалить все штрих-коды, которые больше не существуют в запросе $product->barcodes()->whereNotIn('id', $barcodeSync)->delete();

  3. Он создаст любой новый штрих-код, переданный в запрос, поскольку новые штрих-коды не Если в запросе есть поле id, он запросит идентификатор 0 (0 не будет), что вызовет создание нового штрих-кода и присвоение его продукту. (чтобы это работало, также убедитесь, что поле id вашей модели штрих-кода не находится в массиве $fillable, потому что он будет пытаться установить id равным 0 каждый раз, когда вы создаете новый штрих-код, что приведет к ошибке)

Надеюсь, это вам поможет!

0 голосов
/ 07 мая 2020

Я думаю, это потому, что, когда данные отправляются на сервер, они также содержат старые данные.

Этот код всегда создает новый и не обновляет его.

$barcode = new Barcode;
.
.
.
$barcode->save();

Может быть, вы могли бы что-то вроде этого.

https://laravel.com/docs/7.x/eloquent#other -creation-methods

foreach($request->input('barcodes') as $bb)
{
  if(!empty($bb['serial_number'])){ // make sure no empty value saves
   /* Update the row where has serial number or create a one */
    Barcode::updateOrCreate([
      'serial_number' => $bb['serial_number'] // if serial number is unique. 
      'product_id'    => $product->id
    ], [ 
      'serial_number' => $bb['serial_number'],
      'product_id'    => $product->id,
    ]);
  }
}

Используйте серийный номер, чтобы найти штрих-код и обновить его. Если штрих-код не найден, создайте новый.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...