Laravel 4, как мне создать начальные данные для таблиц с отношениями?

Я создал базу данных с двумя таблицами: «цели» и «частичные цели». Практическое использование состоит в том, чтобы сделать цель сбережений (деньги) и иметь вехи на этом пути (частичные цели). Я хочу, чтобы частичные цели были явно связаны с конкретной целью. Отношения созданы, но у меня возникают проблемы при попытке создать исходные данные.

Моя цель - настроить две таблицы целей, подобные этой (GoalsTableSeeder.php):

<?php

class GoalsTableSeeder extends Seeder {

    public function run()
    {
        DB::table('goals')->delete();


        $goals = array(
            array(
                'max'      => 1850000,
                'avgsav' => 3500,
                'duedate'  => date('2015-03-15'),
                'created_at' => new DateTime,
                'updated_at' => new DateTime,
            ),
            array(
                'max'      => 1100000,
                'avgsav' => 5000,
                'duedate'  => date('2013-11-15'),
                'created_at' => new DateTime,
                'updated_at' => new DateTime,
            )
        );

        DB::table('goals')->insert( $goals );
    }

}

И моя таблица частичных целей выглядит так (PartgoalsTableSeeder.php):

<?php

class PartgoalsTableSeeder extends Seeder {

    public function run()
    {
        DB::table('partgoals')->delete();


        $partgoals = array(
            array(
                'id' => 1,
                'milestone'      => 100000,
                'duedate'  => date('2014-03-15'),
                'created_at' => new DateTime,
                'updated_at' => new DateTime,
            ),
            array(
                'id' => 1,
                'milestone'      => 20000,
                'duedate'  => date('2013-06-15'),
                'created_at' => new DateTime,
                'updated_at' => new DateTime,
            ),
            array(
                'id' => 2,
                'milestone'      => 400000,
                'duedate'  => date('2013-09-15'),
                'created_at' => new DateTime,
                'updated_at' => new DateTime,
            ),
            array(
                'id' => 2,
                'milestone'      => 200000,
                'duedate'  => date('2014-10-15'),
                'created_at' => new DateTime,
                'updated_at' => new DateTime,
            )
        );

        DB::table('partgoals')->insert( $partgoals );
    }

}

Таблица миграции для "целей":

<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateGoalsTable extends Migration {

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('goals', function(Blueprint $table)
        {
            $table->increments('id');
            $table->integer('max');
            $table->float('avgsav');
            $table->date('duedate');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('goals');
    }

}

Таблица миграции для партголов:

<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreatePartgoalsTable extends Migration {

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('partgoals', function(Blueprint $table)
        {
            $table->foreign('id')
                ->references('id')->on('goals')
                ->onDelete('cascade');
            $table->increments('id');
            $table->float('milestone');
            $table->date('duedate')->nullable();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('partgoals');
    }

}

Что я делаю не так? Я новичок в Laravel (и Laravel 4).


person Mårten Cederman    schedule 30.06.2013    source источник
comment
Возможно, вам было бы полезно описать проблему, с которой вы столкнулись. Есть ли конкретное сообщение об ошибке/предупреждение? ваши данные отсутствуют/как и ожидалось? и т.п.   -  person Chris    schedule 30.06.2013
comment
Извините, сначала я казался очевидным =) Я получаю эту проблему в консоли: [Исключение] SQLSTATE [23000]: Нарушение ограничения целостности: 1062 Повторяющаяся запись '1' для ключа 'PRIMARY' (SQL: вставить в partgoals (id, milestone , duedate, created_at, updated_at) значения (?, ?, ?, ?, ?), (?, ? , ?, ?, ?), (?, ?, ?, ?, ?), (?, ?, ? , ?, ?)) Вместе с данными хочу вставить.   -  person Mårten Cederman    schedule 01.07.2013


Ответы (4)


Я вижу несколько проблем с вашим кодом:

1) Способ создания внешнего ключа
При назначении ограничения внешнего ключа вы должны сделать этот столбец unsignedInteger.
В приведенном ниже коде я исправлю вашу ошибку. именования двух столбцов 'id'.

Schema::create('partgoals', function(Blueprint $table)
    {
        $table->increments('id');        
        $table->unsignedInteger('goal_id');
        $table->foreign('goal_id')
            ->references('id')->on('goals')
            ->onDelete('cascade');
        $table->float('milestone');
        $table->date('duedate')->nullable();
        $table->timestamps();
    });


2) Способ заполнения базы данных
Если вы укажете внешний ключ, вы должны объявить значение при создании записи в загрузчике таблиц.
Если вы хотите указать значение NULL, это можно сделать, разрешив столбцу принимать такое значение (по умолчанию это не так). В этом случае мы должны добавить ->nullable()->default(NULL)

Schema::create('partgoals', function(Blueprint $table)
    {
        $table->increments('id');        
        $table->unsignedInteger('goal_id')->nullable()->default(NULL);
        $table->foreign('goal_id')
            ->references('id')->on('goals')
            ->onDelete('cascade');
        $table->float('milestone');
        $table->date('duedate')->nullable();
        $table->timestamps();
    });

Небольшая ошибка
3) Вы дважды передаете 'id' => 1 в сеялке

person clod986    schedule 16.10.2013
comment
Где в файловой структуре Laravel находится этот файл? - person Andrew Koper; 29.12.2013
comment
@ЭндрюКопер app/database/migrations - person lozadaOmr; 18.06.2014
comment
Можете ли вы привести пример того, что вы подразумеваете под объявлением значения при создании записи, я также пытаюсь заполнить реляционную базу данных - person Miguel Stevens; 25.08.2014
comment
просто используйте 'field' => 'value'. Суть этой части заключалась в следующем: внешний ключ должен быть установлен, если он не обнуляемый - person clod986; 02.09.2014

При использовании increments в построителе запросов это автоматически делает ваш первичный ключ автоматически увеличивающимся и уникальным. У вас не может быть внешний ключ также вашим первичным ключом, если это не отношение один к одному. Хотя это просто плохой дизайн. Ваша схема должна выглядеть примерно так, как показано ниже.

Schema::create('partgoals', function(Blueprint $table)
    {
        $table->increments('id');
        $table->foreign('goal_id')
            ->references('id')->on('goals')
            ->onDelete('cascade');
        $table->float('milestone');
        $table->date('duedate')->nullable();
        $table->timestamps();
    });

Кроме того, при заполнении, если вы используете insertGetId при вставке, он вернет идентификатор записи, которую вы только что вставили. Это вы можете использовать в другой вставке, например, в другой таблице позже. Однако это должно происходить в том же сценарии. Возможно, вы сможете передать его обратно в DatabaseSeeder, а затем обратно в другой исходный скрипт, но я этого не пробовал.

person searsaw    schedule 10.07.2013

Я не знаком с Laravel или с тем, что вы пытаетесь сделать, но на основе ошибки, которую вы добавили в комментариях, кажется, что ваша проблема является результатом попытки ввести несколько записей с одним и тем же первичным ключом (1) в ваш partgoals стол.

Я не уверен, как вы настроили свои таблицы, но похоже, что вы определили таблицу partgoals с уникальным столбцом первичного ключа ID, который вы также пытаетесь использовать в качестве внешнего ключа для ссылки на таблицу goals . Возможно, стоит создать еще одно поле для хранения внешнего ключа в таблице partgoals.

person Chris    schedule 30.06.2013

Чтобы заполнить таблицы отношениями, вам необходимо определить фабрики моделей в файле ModelFactory.php, а затем создать класс сеялки для запуска сеялки.

Например ModelFactory.php

$factory->define(App\Category::class, function (Faker\Generator $faker) {

    $name = $faker->name;

    return [
        'name' => $name,
        'visible' => 1
    ];
});

$factory->define(App\Video::class, function (Faker\Generator $faker) {

    return [
        'title' => $faker->name,
        'description' => '',
        'status' => 1
    ];
});

Тогда класс сеялки может быть следующим

<?php

use Illuminate\Database\Seeder;

class CategoriesTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $categories = factory(App\Category::class, 20)->create()->each(function ($u) {
                for ($i=0; $i<5; $i++)
                {
                    $u->videos()->save(factory(App\Video::class)->make());
                }
            });
    }
}

Вы можете обратиться к этой статье о том, как сгенерировать начальные значения для двух таблиц с отношением http://deepdivetuts.com/seeding-two-tables-using-laravel-5-3

person Joel Fernandes    schedule 27.01.2017