Llenar una base de datos en un archivo de migración de Laravel

8 minutos de lectura

avatar de usuario
adam hopkinson

Estoy aprendiendo Laravel y tengo un archivo de migración en funcionamiento que crea una tabla de usuarios. Estoy tratando de completar un registro de usuario como parte de la migración:

public function up()
{
    Schema::create('users', function($table){

        $table->increments('id');
        $table->string('email', 255);
        $table->string('password', 64);
        $table->boolean('verified');
        $table->string('token', 255);
        $table->timestamps();

        DB::table('users')->insert(
            array(
                'email' => `[email protected]`,
                'verified' => true
            )
        );

    });
}

Pero recibo el siguiente error cuando ejecuto php artisan migrate:

SQLSTATE[42S02]: Base table or view not found: 1146 Table 'vantage.users' doesn't exist

Obviamente, esto se debe a que Artisan aún no ha creado la tabla, pero toda la documentación parece decir que hay una manera de usar Fluent Query para completar datos como parte de una migración.

¿Alguien sabe cómo?

avatar de usuario
BenjamínRH

No coloque DB::insert() dentro de Schema::create(), porque el método de creación tiene que terminar de hacer la tabla antes de que pueda insertar cosas. Prueba esto en su lugar:

public function up()
{
    // Create the table
    Schema::create('users', function($table){
        $table->increments('id');
        $table->string('email', 255);
        $table->string('password', 64);
        $table->boolean('verified');
        $table->string('token', 255);
        $table->timestamps();
    });

    // Insert some stuff
    DB::table('users')->insert(
        array(
            'email' => '[email protected]',
            'verified' => true
        )
    );
}

  • y cómo insertar múltiples datos?

    – Sahbaz

    28 de febrero de 2018 a las 11:31

  • @SuperMario’sYoshi creo que algo como esto DB::table('users')->insert([ ['email' => '[email protected]', 'votes' => 0], ['email' => '[email protected]', 'votes' => 0] ]);

    – Денис

    16 de abril de 2019 a las 5:19

avatar de usuario
darrylkuhn

Sé que esta es una publicación antigua, pero como aparece en una búsqueda en Google, pensé en compartir algunos conocimientos aquí. @erin-geyer señaló que mezclar migraciones y seeders puede crear dolores de cabeza y @justamartin respondió que a veces desea/necesita que se completen los datos como parte de su implementación.

Yo iría un paso más allá y diría que a veces es deseable poder implementar cambios de datos de manera consistente para que pueda, por ejemplo, implementarlos en la etapa de pruebas, ver que todo esté bien y luego implementarlos en producción con la confianza de obtener los mismos resultados. (y no tener que recordar ejecutar algún paso manual).

Sin embargo, todavía tiene valor separar la semilla y la migración, ya que son dos preocupaciones relacionadas pero distintas. Nuestro equipo se ha comprometido al crear migraciones que llaman a seeders. Esto parece:

public function up()
{
    Artisan::call( 'db:seed', [
        '--class' => 'SomeSeeder',
        '--force' => true ]
    );
}

Esto le permite ejecutar una semilla una vez como una migración. También puede implementar una lógica que evite o aumente el comportamiento. Por ejemplo:

public function up()
{
    if ( SomeModel::count() < 10 )
    {
        Artisan::call( 'db:seed', [
            '--class' => 'SomeSeeder',
            '--force' => true ]
        );
    }
}

Obviamente, esto ejecutaría condicionalmente su sembradora si hay menos de 10 SomeModels. Esto es útil si desea incluir la sembradora como una sembradora estándar que se ejecuta cuando llama artisan db:seed así como cuando migre para que no se “doble”. También puede crear una sembradora inversa para que las reversiones funcionen como se esperaba, por ejemplo

public function down()
{
    Artisan::call( 'db:seed', [
        '--class' => 'ReverseSomeSeeder',
        '--force' => true ]
    );
}

El segundo parámetro --force es necesario para permitir que Seeder se ejecute en un entorno de producción.

  • Esta es, de lejos, la mejor respuesta. ¡Código mantenible que separa preocupaciones!

    – helsont

    12 de mayo de 2016 a las 4:58

  • Tendría cuidado de considerar las implicaciones a largo plazo de llamar a seeders desde scripts de migración. Los scripts de migración tienen versiones de fecha y hora, mientras que los seeders normalmente no lo tienen. Durante el desarrollo, las necesidades del sembrador cambian a menudo, lo que da como resultado la posibilidad de que los scripts de migración con versiones ejecuten sembradores sin versiones, rompiendo la idempotencia. En otras palabras, ejecutar el mismo conjunto de scripts de migración día a día podría generar resultados diferentes.

    – originalbryan

    28 de febrero de 2017 a las 23:52


  • Ha pasado un tiempo desde que publiqué esto y quería compartir nuestra experiencia con esta técnica. En general, ha funcionado bien para nosotros y si tuviera que hacerlo de nuevo, lo haría. Dicho esto, hay un problema a tener en cuenta. @originalbryan tiene toda la razón y la consecuencia es que ocasionalmente nos encontramos con situaciones en las que las migraciones se interrumpen al activar una base de datos nueva porque, a medida que las migraciones se ejecutan, el sembrador (y el modelo) están más actualizados que la base de datos (ya que podemos sembrar antes de que el esquema se actualice por completo). Cuando eso sucede, actualizamos la migración anterior para solucionar el problema.

    – darrylkuhn

    04/04/2017 a las 16:45


  • @darrylkuhn sí, tu propuesta rompe esa regla. Si no llamamos a seeder dentro del archivo de migración pero colocamos ‘INSERT-s’ directamente en el archivo de migración, entonces hemos guardado la consistencia de los datos sin cambiar los archivos de migración antiguos. De hecho, claramente no veo ningún problema con poner INSERT en los archivos de migración; por ejemplo, tengo un sistema con 30 tablas y quiero agregar una nueva característica que necesita una nueva tabla con algunos datos iniciales, así que pongo esos datos iniciales en el archivo de migración (en un método separado) – no hay problema 😛

    – Kamil Kielczewski

    17 de agosto de 2017 a las 5:25


  • Todo el lenguaje de Laravel implica que una sembradora es para datos de prueba, por lo que creo que debe tenerse en cuenta con el diseño. Es importante distinguir entre los datos que forman parte de la aplicación y los datos de prueba, e incluir los datos requeridos directamente en una migración hace que la distinción sea muy clara.

    – Brettins

    18 sep 2019 a las 17:55

avatar de usuario
erin geyer

Aquí hay una muy buena explicación de por qué usar el Sembrador de bases de datos de Laravel es preferible a usar Migraciones: https://web.archive.org/web/20171018135835/http://laravelbook.com/laravel-database-seeding/

Aunque seguir las instrucciones en la documentación oficial es una idea mucho mejor porque la implementación descrita en el enlace anterior no parece funcionar y está incompleta. http://laravel.com/docs/migrations#database-seeding

  • Estoy de acuerdo contigo Erin. No mezcle migraciones con datos inicializados porque es muy probable que desee inicializar algunos datos en su entorno de desarrollo pero no en su entorno de producción.

    –Daniel Vigueras

    8 de septiembre de 2014 a las 7:47


  • Buen punto, pero hay algunas situaciones en las que deben existir algunos datos en el entorno de producción. Por ejemplo, debe existir el primer usuario administrador predeterminado para que el cliente pueda iniciar sesión por primera vez, deben existir algunos roles de autorización preestablecidos, algunos datos de lógica comercial también pueden ser necesarios de inmediato. Por lo tanto, creo que se deben agregar datos obligatorios a las migraciones (para que también pueda subir/bajar registros de datos a través de migraciones separadas), pero las semillas se pueden dejar para el desarrollo.

    – JustAMartin

    10 de abril de 2015 a las 6:55


  • Una pequeña nota; el enlace a la inicialización de la base de datos es ahora: laravel.com/docs/5.3/siembra

    – magikMaker

    18 oct 2016 a las 0:10

  • Incluya la parte relevante de los artículos vinculados. Se desaconsejan las respuestas de solo enlace. ¡Tu primer enlace ya está muerto y tuve que recuperarlo de archive.org!

    – totymedli

    8 oct 2020 a las 20:04

Si está utilizando Laravel 8 y le gustaría inicializar con múltiple registros puedes hacerlo de cualquiera de estas dos formas.

1. La forma no recomendada

public function up()
    {
        Schema::create('categories', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->timestamps();
        });

        DB::table('categories')->insert(
            array(
                [
                    'name' => 'Category1',
                ],
                [
                    'name' => 'Category2',
                ],
                [
                    'name' => 'Category3',
                ],
            )
        );
    }

El método anterior está bien, pero dejará el Creado en y actualizado_en columnas en blanco.

2. El Camino recomendado

 public function up()
    {
        Schema::create('categories', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->timestamps();
        });


        $data =  array(
            [
                'name' => 'Category1',
            ],
            [
                'name' => 'Category2',
            ],
            [
                'name' => 'Category3',
            ],
        );
        foreach ($data as $datum){
            $category = new Category(); //The Category is the model for your migration
            $category->name =$datum['name'];
            $category->save();
        }

    }

avatar de usuario
cuerdas28

Esto debería hacer lo que quieras.

public function up()
{
    DB::table('user')->insert(array('username'=>'dude', 'password'=>'z19pers!'));
}

Otra forma limpia de hacerlo es definir un método privado que cree una instancia y persista el modelo en cuestión.

public function up()
{
    Schema::create('roles', function (Blueprint $table) {
        $table->increments('id');
        $table->string('label', 256);
        $table->timestamps();
        $table->softDeletes();
    });

    $this->postCreate('admin', 'user');
}

private function postCreate(string ...$roles)  {
    foreach ($roles as $role) {
        $model = new Role();
        $model->setAttribute('label', $role);
        $model->save();
    }
}

Con esta solución, Eloquent generará campos de marcas de tiempo.

EDITAR: es mejor usar el sistema seeder para diferenciar la generación de la estructura de la base de datos y la población de la base de datos.

Probé este método de inserción de DB, pero como no usa el modelo, ignoró un rasgo de sluggable que tenía en el modelo. Entonces, dado que existe el modelo para esta tabla, tan pronto como se migró, pensé que el modelo estaría disponible para usar para insertar datos. Y se me ocurrió esto:

public function up() {
        Schema::create('parent_categories', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name');
            $table->string('slug');
            $table->timestamps();
        });
        ParentCategory::create(
            [
                'id' => 1,
                'name' => 'Occasions',
            ],
        );
    }

Esto funcionó correctamente y también tuvo en cuenta el rasgo de sluggable en mi Modelo para generar automáticamente un slug para esta entrada, y también usa las marcas de tiempo. NÓTESE BIEN. No fue necesario agregar la identificación, sin embargo, quería identificaciones específicas para mis categorías en este ejemplo. Probado trabajando en Laravel 5.8

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad