如何在 Laravel 中导入具有各种模型(和子数据/模型)的单个 excel 文件/工作表?

Posted

技术标签:

【中文标题】如何在 Laravel 中导入具有各种模型(和子数据/模型)的单个 excel 文件/工作表?【英文标题】:How to import a single excel file/sheet with various Models (and sub-data/models) in Laravel? 【发布时间】:2019-01-10 13:42:40 【问题描述】:

根据标题,我在每一行中都有一个包含数据(父/子)的 Excel 文件。 Laravel Excel 网站展示了如何导入,假设每行有一个模型 - 但是如何导入子数据? https://laravel-excel.maatwebsite.nl/3.1/imports/

例如“伪”架构:

    Schema::create('students', function (Blueprint $table) 
        $table->increments('id')->unsigned()->index();
        $table->string('student_code',16);
        $table->string('student_name',64);
        $table->string('student_surname',64);
    );
    Schema::create('student_courses', function (Blueprint $table) 
        $table->increments('id')->unsigned()->index();
        $table->integer('student_id')->unsigned()->index();
        $table->string('course', 32);
        $table->date('start_date');
        $table->date('end_date');
        $table->timestamps();
    );
    Schema::create('student_contacts', function (Blueprint $table) 
        $table->increments('id')->unsigned()->index();
        $table->integer('student_id')->unsigned()->index();
        $table->string('contact_name', 32);
        $table->string('contact_number', 32);
        $table->timestamps();
    );

例如文件:students.xlsx

Student Code | Student Name | Student Surname | Course  | Course Start Date | Course End Date | Contact Person | Contact Numbers
ABC1         | Arnold       | Clarp           | C++     | 2019-01-01        | 2019-12-01      | Boogle         | 555-111-222
DEF2         | Delta        | Flork           | English | 2019-01-02        | 2019-12-02      | Google         | 555-111-333
GHI3         | Goblin       | Clark           | Science | 2019-01-03        | 2019-12-03      | Foogle         | 555-111-444

假设我的导入代码:

class StudentsImport implements ToModel, WithStartRow

/**
* @param array $row
*
* @return \Illuminate\Database\Eloquent\Model|null
*/
public function model(array $row)

    return new Student([
        'student_code'                  => $row[1],
        'student_name'              => $row[2],
        'student_surname'               => $row[3],
    ]);


/**
* @return int
*/
public function startRow(): int

    return 2;


我实际上会在哪里插入“儿童”课程/联系人数据的导入? 我猜不是'返回一个新学生' - 我实际上会先将它分配给一个变量,然后再导入它?这是正确的方法吗? 例如:

public function model(array $row)

    $student = new Student([
        'student_code'=> $row[1],
        'student_name'=> $row[2],
        'student_surname'=> $row[3],
    ])
    $student->courses()->create([
        'course'=>$row[4],
        'start_date'=>$row[5],
        'end_date'=>$row[6]
    ]);
    $student->contacts()->create([
        'contact_name'=>$row[7],
        'contact_number'=>$row[8]
    ]);
    return $student;

//实际代码,不再是“伪”:

    $student = new Student([
        'bursary_provider_id' => 1,
        'bursary_provider_reference' => 'xxx',
        'student_name' => $row[1],
        'student_initials' => $row[3],
        'student_surname' => $row[2],
        'passport_number' => $row[7],
        'passport_expiration' => \phpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($row[9]),
        'country_id' => 7,
        'id_number' => $row[6],
        'status' => $status,
        'notes' => $row[5]
    ]);

    if (isset($row[10])) 
        $student->visas()->create([
            'country_id' => 201,
            'visa_reference_number' => $row[10],
            'visa_expiration_date' => \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($row[11])
        ]);

错误(它没有通过父 id)

SQLSTATE[23000]:违反完整性约束:1048 列“student_id”不能为空(SQL:插入student_visascountry_idvisa_reference_numbervisa_expiration_datestudent_idupdated_at、@ 987654333@) 值 (201, ABCHFV4, 2019-12-31 00:00:00, , 2019-01-11 08:03:06, 2019-01-11 08:03:06))

【问题讨论】:

应该可以。你遇到什么麻烦了吗? 我是 Laravel 菜鸟,我不确定这样做的正确方法,所以还没有完成这个过程 - 想确保我做得正确...... 检查我的编辑 ^ 我可以确认它实际上不起作用 - 父 ID 没有通过... 您在student_visas 中有一个不能为空的列student_id。我们可以看到StudentStudentVisa 之间的关系定义吗? :) 我的理解是父ID为空,因为这个阶段student实际上还没有被插入到数据库中。 Laravel Excel 似乎只在最后插入。与我的关系无关 - 虽然为了清楚起见,我确实有一个外键设置。 【参考方案1】:

您收到错误是因为学生尚未写入数据库,因此没有为新学生实例分配 id。如果您使用集合,则数据会立即写入数据库。在模型函数中你可以使用

$student=Student::Create(['bursary_provider_id' => 1,
    'bursary_provider_reference' => 'xxx',
    'student_name' => $row[1],
    'student_initials' => $row[3],
    'student_surname' => $row[2],
    'passport_number' => $row[7],
    'passport_expiration' => \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($row[9]),
    'country_id' => 7,
    'id_number' => $row[6],
    'status' => $status,
    'notes' => $row[5]]);

这会将学生写入数据库并生成必要的 ID。不过我不确定这会如何影响性能。

【讨论】:

【参考方案2】:

答案(不要问我为什么,因为现阶段的文档很差)是使用集合。

use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;

而不是 ToModel:

public function collection(Collection $rows)

它不会“返回”任何东西。除了这些更改之外,在 OP 中使用完全相同的代码可以按预期工作。

【讨论】:

以上是关于如何在 Laravel 中导入具有各种模型(和子数据/模型)的单个 excel 文件/工作表?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Laravel 项目中导入和使用 vue-good-table Vue 组件

如何使用 laravel 5.7 和 vue JS 在 mysql 中导入 excel 文件

如何在我的laravel应用程序中导入Code ckeditor?

如何在 play 框架模型中导入 java 扩展?

Tailwind 没有在 Laravel 中导入

如何在 Django 中导入用户模型并选择所有对象