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

115

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 al ejecutar 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 forma de usar Fluent Query para completar datos como parte de una migración.

Alguien sabe como? ¡Gracias!

Adam Hopkinson
fuente

Respuestas:

215

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
        )
    );
}
BenjaminRH
fuente
5
y como insertar varios datos?
Sahbaz
6
@ SuperMario'sYoshi creo que algo como estoDB::table('users')->insert([ ['email' => '[email protected]', 'votes' => 0], ['email' => '[email protected]', 'votes' => 0] ]);
Денис
80

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 la combinación de migraciones y sembradoras puede crear dolores de cabeza y @justamartin respondió que a veces desea / necesita que los datos se completen 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, implementar en la etapa de pruebas, ver que todo está bien y luego implementar en producción con la confianza de los mismos resultados. (y no tener que acordarse de ejecutar algún paso manual).

Sin embargo, todavía es útil 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 sembradoras. Esto se parece a:

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

Esto le permite ejecutar una semilla una vez como si fuera una migración. También puede implementar la lógica que previene o aumenta 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 tanto cuando llama artisan db:seedcomo cuando migra para no "duplicar". También puede crear una sembradora inversa para que los retrocesos funcionen como se espera, p. Ej.

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

El segundo parámetro --forcees necesario para permitir que la sembradora funcione en un entorno de producción.

darrylkuhn
fuente
2
Esta es, con mucho, la mejor respuesta. ¡Código mantenible que separa preocupaciones!
helsont
18
Tendría cuidado de considerar las implicaciones a largo plazo de llamar a sembradoras desde scripts de migración. Los scripts de migración tienen versiones de fecha / hora, mientras que las sembradoras normalmente no. Durante el desarrollo, las necesidades de las sembradoras cambian a menudo, lo que da como resultado la posibilidad de que los scripts de migración versionados ejecuten sembradoras no versionadas, rompiendo la idempotencia. En otras palabras, ejecutar el mismo conjunto de scripts de migración día a día podría producir resultados diferentes.
originalbryan
2
Ha pasado un tiempo desde que publiqué esto y quería brindar nuestra experiencia utilizando esta técnica. En general, nos ha funcionado bien y si tuviera que hacerlo de nuevo, lo haría. Dicho esto, hay un problema que debes 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 hacer girar una base de datos nueva porque, a medida que se ejecutan las migraciones, 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
@darrylkuhn Escuché que no es una buena práctica actualizar los archivos de migración antiguos; en lugar de actualizar los archivos antiguos, debe crear un nuevo archivo de migración; este es el "flujo de trabajo" para los archivos de migración por diseño
Kamil Kiełczewski
2
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 esa distinción sea muy clara.
Brettins
13

Aquí hay una muy buena explicación de por qué usar Database Seeder de Laravel es preferible a usar Migraciones: http://laravelbook.com/laravel-database-seeding/

Sin embargo, seguir las instrucciones de 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

Erin Geyer
fuente
1
Estoy de acuerdo contigo Erin. No mezcle migraciones con datos de inicialización porque es muy probable que desee inicializar algunos datos en su entorno de desarrollo pero no en su entorno de producción.
Daniel Vigueras
18
Buen punto, pero hay algunas situaciones en las que deben existir algunos datos en el entorno de producción. Por ejemplo, el primer usuario administrador predeterminado debe existir para que el cliente pueda iniciar sesión por primera vez, deben existir algunos roles de autorización preestablecidos, algunos datos de lógica empresarial también pueden ser necesarios de inmediato. Por lo tanto, creo que los datos obligatorios deben agregarse a las migraciones (para que pueda subir / bajar también los registros de datos a través de migraciones separadas), pero las semillas se pueden dejar para el desarrollo.
JustAMartin
Una pequeña nota; el enlace a la siembra de la base de datos ahora es: laravel.com/docs/5.3/seeding
magikMaker
3

Esto debería hacer lo que quieras.

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

Otra forma limpia de hacerlo es definir un método privado que cree la 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, los campos de marcas de tiempo serán generados por Eloquent.

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

Maximilien DI DIO
fuente
Me gusta este ... sirve exactamente lo que necesitaba hacer, agregue algunos roles de usuario de forma predeterminada en la migración. Necesito asegurarse de importar el modelo o hacer referencia directamente a él $model = new App\UserRoles();, pero aparte de eso ... ¡perfecto!
FAB
1

Probé este método de inserción de base de datos, 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 migre, pensé que el modelo estaría disponible 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 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 era 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

Andrew Arscott
fuente
0

Si ya ha llenado columnas y ha agregado una nueva o desea completar la columna anterior con nuevos valores simulados, haga esto:

public function up()
{
    DB::table('foydabars')->update(
        array(
            'status' => '0'
        )
    );
}
CodeToLife
fuente