[php] 라 라벨이 피벗 테이블에 여러 레코드를 추가하는 것을 방지

내가 사용하는 장바구니에 항목을 추가하기 위해 다 대다 관계를 설정하고 작업 중입니다.

$cart->items()->attach($item);

피벗 테이블에 항목을 추가하지만 사용자가 이미 추가 한 항목을 추가하기 위해 링크를 다시 클릭하면 피벗 테이블에 중복 항목이 생성됩니다.

레코드가 아직 존재하지 않는 경우에만 피벗 테이블에 레코드를 추가하는 기본 방법이 있습니까?

그렇지 않은 경우 일치하는 레코드가 이미 있는지 찾기 위해 피벗 테이블을 어떻게 확인할 수 있습니까?



답변

다음과 같이 매우 간단한 조건을 작성하여 기존 레코드의 존재를 확인할 수 있습니다.

if (! $cart->items->contains($newItem->id)) {
    $cart->items()->save($newItem);
}

또는 / 그리고 데이터베이스에 단일성 조건을 추가 할 수 있습니다. 이중선을 저장하는 동안 예외가 발생합니다.

또한 바로 아래 Barryvdh의보다 간단한 답변을 살펴보아야합니다.


답변

$model->sync(array $ids, $detaching = true)메서드를 사용하고 분리를 비활성화 할 수도 있습니다 (두 번째 매개 변수).

$cart->items()->sync([$item->id], false);

업데이트 : Laravel 5.3 또는 5.2.44부터 syncWithoutDetaching을 호출 할 수도 있습니다.

$cart->items()->syncWithoutDetaching([$item->id]);

정확히 동일하지만 더 읽기 쉽습니다. 🙂


답변

@alexandre Butynsky 방법은 매우 잘 작동하지만 두 개의 SQL 쿼리를 사용합니다.

하나는 장바구니에 항목이 있는지 확인하고 하나는 저장합니다.

하나의 쿼리 만 사용하려면 다음을 사용하십시오.

try {
    $cart->items()->save($newItem);
}
catch(\Exception $e) {}


답변

이 모든 답변이 내가 모든 답변을 시도했기 때문에 좋은 것처럼, 아직 답변이 없거나 처리되지 않은 한 가지가 있습니다. 이전에 확인한 값을 업데이트하는 문제입니다 (선택된 상자를 선택하지 않음). 위의 질문과 비슷한 것이 내 제품 기능 테이블 (피벗 테이블)에서 제품의 기능을 확인하고 선택 취소하고 싶습니다. 나는 초보자이고 위의 어느 것도 그렇게하지 않았다는 것을 깨달았습니다. 새 기능을 추가 할 때는 둘 다 좋지만 기존 기능을 제거하고 싶을 때 (즉 선택 취소)

나는 이것에 대한 어떤 깨달음을 감사드립니다.

$features = $request->get('features');

if (isset($features) && Count($features)>0){
    foreach ($features as $feature_id){
        $feature = Feature::whereId($feature_id)->first();
        $product->updateFeatures($feature);
    }
}

//product.php (extract)
public function updateFeatures($feature) {
        return $this->features()->sync($feature, false);
}

또는

public function updateFeatures($feature) {
   if (! $this->features->contains($features))
        return $this->features()->attach($feature);
}
//where my attach() is:
public function addFeatures($feature) {
        return $this->features()->attach($feature);
}

죄송합니다. 질문을 삭제해야하는지 잘 모르겠습니다. 답을 직접 알아 냈기 때문에 약간 어리석게 들립니다. 위의 답변은 다음과 같이 @Barryvdh sync () 작업만큼 간단합니다. 다음에 대해 점점 더 많이 읽었습니다.

$features = $request->get('features');
if (isset($features) && Count($features)>0){
    $product->features()->sync($features);
}


답변

그냥 사용할 수 있습니다

$cart->items()->sync($items)

Laravel 5.7 기준 :

연결 동기화 sync 메서드를 사용하여 다 대다 연결을 구성 할 수도 있습니다. sync 메서드는 중간 테이블에 배치 할 ID 배열을 허용하며, 지정된 배열에없는 모든 ID는 중간 테이블에서 제거됩니다. 따라서이 작업이 완료되면 지정된 배열의 ID 만 중간 테이블에 존재합니다.


답변

이미 게시 된 몇 가지 훌륭한 답변이 있습니다. 나는 이것도 여기에 버리고 싶었다.

@AlexandreButynski와 @Barryvdh의 답변은 내 제안보다 더 읽기 쉽습니다.이 답변이 추가하는 것은 효율성입니다.

현재 조합 (실제로는 id 만)에 대한 항목 만 검색하고 존재하지 않는 경우 첨부하는 것보다 검색합니다. 동기화 메소드 (분리 없이도)는 현재 연결된 모든 ID를 검색합니다. 반복이 적은 작은 세트의 경우 이것은 거의 차이가 없을 것입니다.

어쨌든, 확실히 읽을 수는 없지만 트릭을 수행합니다.

if (is_null($book->authors()->find($author->getKey(), [$author->getQualifiedKeyName()])))
    $book->authors()->attach($author);


답변