질문을 삭제하지 말아주세요.!
 
1
0
-1

https://laravel.kr/docs/5.5/eloquent#mass-assignment

여기 문서보고 작업하고 있는데

대량으로 여러개의 레코드를 넣고 싶습니다.

그래서 

$arr = [];

foreach($request_arr as $a) {
    $arr[] = ['name'=>$a→name, 'age'=>$a->age....];
}

Info::create($arr);

이런식으로 했는데

SQLSTATE[HY000]: General error: 1364 Field 'field_name' doesn't have a default value

이런 에러가 나타납니다.

해당 모델의 protected $fillable로 대량으로 들어갈 컬럼을 모두 정의해 주고요...

어떤게 문제 일까요?

    CommentAdd your comment...

    3 answers

    1.  
      2
      1
      0

      field_name 값이 null 인 값이 혹시 있나요??

      1. lzao

        아뇨, 값도 모두 확인해봤는데 null값인 것 없었어요.

        혹시 몰라서 text로도 그냥 넣어봤는데 동일한 에러가 나타납니다.


      CommentAdd your comment...
    2.  
      2
      1
      0

      아주 간단한 서비스라면 MassAssignment를 허용하고 create()를 쓰거나, DB::insert()나 update() API를 이용해도 무방합니다. 다만, insert()나 update()등은 엘로퀀트를 거치지 않으므로, 지적하신대로 타임스탬프등이 셋팅되지 않을 뿐더러, 모델 이벤트도 발생하지 않습니다.


      규모가 있는, 계속 유지보수해야 하는 코드라면 아래와 같은 스타일을 참고해보세요.

      // 컨트롤러, 큐 잡, 또는 콘솔 등 딜리버리 메커니즘과 관련된 플로우 컨트롤러
      public function handleRequest()
      {    
          Log::info('데이터 대량 등록 작업을 시작합니다.');
          $candidates = $this->getCandidates();
      
          foreach ($candidates as $attributes) {
              DB::beginTransaction();
              try {
                  $info = $this->createInfo($attributes);
                  $info->save();
                  DB::commit();
              } catch (Exception $e) {
                  DB::rollBack();
                  Log::error($e->getMessage(), ['attributes' => $attributes]);
                  throw $e; // or Just continue;
              }
          }
      	
          Log::info('데이터 대량 등록 작업을 마칩니다.');
      
          return '성공 응답'; // 쉘 메시지, HTTP 응답, 웹훅 등등.
      }
      
      // 컨트롤러의 멤버 함수로 썼지만, Request/Command/JobDto 등의 역할입니다.
      // 컨트롤러에서 Request 객체를 주입 받아서 데이터를 얻어올 수 있도록 하면 좋겠네요.
      private function getCandidates()
      {
          // 콘솔 또는 웹 클라로부터 받은 데이터라 가정합니다.
          // 엑셀에서 읽은 대용량 데이터일 수도 있겠네요.
          // array보다는 Collection으로 반환하면 더 좋겠네요.
          return [
              ['name' => 'foo', 'age' => 1],
              ['name' => 'bar', 'age' => 2],
          ];
      }
      
      // 역시 컨트롤러의 멤버 함수로 썼지만, 재사용을 위해 서비스 클래스로 추출하는게 좋겠습니다.
      // 컨트롤러에서 InfoCreator 등의 서비스 클래스를 주입받아서 사용하면 좋겠네요.
      private function createInfo(array $attributes = [])
      {
          if (false === (isset($attributes['name'] && isset($attributes['age']))) {
              throw new Exception('name 또는 age 값이 정의되지 않았습니다.');
          }
      
          $info = new Info;
          $info->name = $attributes['name'] ?? null;
          $info->age = $attributes['age'] ?? null;
      
          return $info;
      }
      1. lzao

        답변 감사합니다.

      CommentAdd your comment...
    3.  
      1
      0
      -1

      Info::create(['name' => 'abc', 'age' => 14],['name' => 'abcdef', 'age' => 15])

      이런식으로 했을 때는 ['name' => 'abc', 'age' => 14] 이 데이터만 들어갑니다.

      Info::create([['name' => 'abc', 'age' => 14],['name' => 'abcdef', 'age' => 15]])

      이렇게 배열을 한번 더 감싸는 경우에 제가 말한 에러가 나타납니다.


      create를 반복문으로 돌려야 하는건가요??

      1. 권윤학

        insert로 사용하시면 됩니다. (smile)

        Model::insert([
        	[....], 
        	[....]
        ]);
      2. lzao

        insert로 사용할 때 자동으로 created_time의 값이 안들어가 던데 이건 그냥 fillable에 해당 필드 넣고 제가 직접 넣으면 되는 거겠죠?

      3. 권윤학

        그렇게 하셔도되고

        db에서 CURRENT_TIMESTAMP으로 디폴트로 잡아놔서 처리하셔도 될듯 합니다.

      4. lzao

        답변 감사합니다 (big grin)

      CommentAdd your comment...