2012-09-27 16 views
6

¿Existe una manera rápida de modificar una consulta SQL generada por Laravel's Fluent para tener un INSERT IGNORE en lugar del habitual?INSERTAR IGNORAR usando Laravel's Fluent

Estoy tratando de insertar una matriz con 50 elementos y escribir toda la consulta manualmente aumentará el código y lo hará más susceptible a los errores humanos.

+0

es la matriz que una clave => par de valores que se corresponde con una configuración de columna => valor? Si es así, simplemente escriba un bucle para generarlo. – wesside

+0

Sí lo hace! :) ¿Quiere escribir un bucle para generar la declaración de consulta SQL? – Nyxynyx

+0

¡Gracias, no sabía que se pueden usar otras bibliotecas de bases de datos! ¿Cómo debo cambiarlo? – Nyxynyx

Respuesta

0

Para el trabajo que necesita para crear una nueva gramática que tiene la cadena bien ahí:

grammar.php(1)

La gramática es una propiedad pública de la DB o en este caso Database conexión almacenada. Esto no es realmente sencillo, pero a partir de la visibilidad de las propiedades, debería poder inyectar su gramática especial en la capa de la base de datos.

También sugiero que traiga el tema al proyecto, probablemente tengan una mejor idea de cómo hacerlo más flexible para casos como estos.


(1) Esta fue una primera, a la fecha de la referencia de respuesta. Si ve esto hoy, debe adoptar la versión de Laravel que usa, p. Grammar.php for 4.0, estas clases se han movido a laravel/framework.

+1

Ese enlace da un 404 ahora. – wiggles

+0

@wiggles: fácil de arreglar. Sin embargo, es posible que el OP no se haya tomado el tiempo de informar esto. – hakre

-13
$your_array = array('column' => 'value', 'second_column' => 'value'); 

DB::table('your_table')->insert($your_array); 

Recuerda, no sé de dónde vienen tus datos, pero debes desinfectarlos siempre. Si tiene más de un registro, simplemente itere en un bucle.

En cuanto a la INSERT IGNORE, encontrar el método INSERT en la biblioteca fluidez, crea un nuevo método llamado insert_ignore de la misma manera como inserto y modificar sólo con el IGNORE.

+0

¿Su consulta realiza un 'INSERT IGNORE'? – Nyxynyx

+0

¿Por qué lo necesita? Nunca especificó – wesside

+3

Especifiqué que en la pregunta ... – Nyxynyx

9

Prueba esta magia, en su modelo:

public static function insertIgnore($array){ 
    $a = new static(); 
    if($a->timestamps){ 
     $now = \Carbon\Carbon::now(); 
     $array['created_at'] = $now; 
     $array['updated_at'] = $now; 
    } 
    DB::insert('INSERT IGNORE INTO '.$a->table.' ('.implode(',',array_keys($array)). 
     ') values (?'.str_repeat(',?',count($array) - 1).')',array_values($array)); 
} 

uso como esto:

Shop::insertIgnore(array('name' => 'myshop')); 

Esta es una gran manera de prevenir violaciónes de restricción que pueden ocurrir con firstOrCreate en un entorno multiusuario , si esa propiedad 'nombre' era una clave única.

+0

Cabe señalar que hacerlo de esta manera es probablemente el camino correcto, pero deberá asegurarse de limpiar todas las variables generadas por el usuario antes de ejecutar la consulta, ¡ya que se trata de SQL sin procesar! –

1

No estoy seguro si útil para nadie, pero recientemente he adaptado el enfoque de hakre a laravel 5:

Tienes que cambiar siguientes 3 archivos para tener su inserción Ignorar trabajo:

  1. En Builder.php (vendedor/laravel/marco/src/iluminar/base de datos/consulta/Builder.php) tiene que CLON el inserto función, con el cambio de nombre a insertIgnore y el cambio en la función de llamada a la gramática: $sql = $this->grammar->compileInsertIgnore($this, $values);)

  2. en Gramo mar.php (vendedor/laravel/framework/src/illuminate/database/query/grammars/Grammar.php) que tiene que clonar la función compileInsert y cambiarle el nombre a compileInsertIgnore, donde puede cambiar retorno a: return "insert ignore into $table ($columns) values $parameters";

  3. En Connection.php (vendedor/laravel/marco/src/iluminar/base de datos/Connection.php) que tiene simplemente clonar el inserto función y cambiarle el nombre a insertIgnore

Ahora se debe hacer, la conexión es capaz de reconocer el insertIgnore función, constructor es capaz de señalar que para corregir la gramática y la gramática incluye 'ignorar' en el declaración. Por favor, esto no funciona bien para MySQL, podría no ser tan fácil para otras bases de datos.

0

Añadir el método de seguimiento insertIgnore a su modelo

<?php 

namespace App; 

use Illuminate\Auth\Authenticatable; 
use Illuminate\Database\Eloquent\Model; 
use Illuminate\Auth\Passwords\CanResetPassword; 
use Illuminate\Foundation\Auth\Access\Authorizable; 
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; 
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract; 
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract; 

class User extends Model implements AuthenticatableContract, 
            AuthorizableContract, 
            CanResetPasswordContract 
{ 
    use Authenticatable, Authorizable, CanResetPassword; 

    /** 
    * The database table used by the model. 
    * 
    * @var string 
    */ 
    protected $table = 'users'; 

    /** 
    * The attributes that are mass assignable. 
    * 
    * @var array 
    */ 
    protected $fillable = ['name', 'email', 'password']; 

    /** 
    * The attributes excluded from the model's JSON form. 
    * 
    * @var array 
    */ 
    protected $hidden = ['password', 'remember_token']; 


    public static function insertIgnore(array $attributes = []) 
    { 
     $model = new static($attributes); 

     if ($model->usesTimestamps()) { 
      $model->updateTimestamps(); 
     } 

     $attributes = $model->getAttributes(); 

     $query = $model->newBaseQueryBuilder(); 
     $processor = $query->getProcessor(); 
     $grammar = $query->getGrammar(); 

     $table = $grammar->wrapTable($model->getTable()); 
     $keyName = $model->getKeyName(); 
     $columns = $grammar->columnize(array_keys($attributes)); 
     $values = $grammar->parameterize($attributes); 

     $sql = "insert ignore into {$table} ({$columns}) values ({$values})"; 

     $id = $processor->processInsertGetId($query, $sql, array_values($attributes)); 

     $model->setAttribute($keyName, $id); 

     return $model; 
    } 
} 

Se puede utilizar:

App\User::insertIgnore([ 
    'name' => 'Marco Pedraza', 
    'email' => '[email protected]' 
]); 

La siguiente consulta se ejecutará:

insert ignore into `users` (`name`, `email`, `updated_at`, `created_at`) values (?, ?, ?, ?) 

Este método añadir automáticamente/elimine las marcas de tiempo Eloquent si ha habilitado o deshabilitado.

1

No pude parchar el mono como se sugiere en la respuesta de Rastislav.

Esto es lo que funcionó para mí:

  1. Anulación compileInsert método en una clase de consulta Gramática costumbre, que se extiende clase MySqlGrammar del marco.

  2. Utilice una instancia de esta clase de gramática personalizada llamando al método setQueryGrammar desde la instancia de conexión de base de datos.

Por lo tanto, el código de clase es la siguiente:

<?php 

namespace My\Namespace; 

use Illuminate\Database\Query\Builder; 
use Illuminate\Database\Query\Grammars\MySqlGrammar; 

/** 
* Changes "INSERT" to "INSERT IGNORE" 
*/ 
class CustomMySqlGrammar extends MySqlGrammar 
{ 
    /** 
    * Compile an insert statement into SQL. 
    * 
    * @param \Illuminate\Database\Query\Builder $query 
    * @param array $values 
    * @return string 
    */ 
    public function compileInsert(Builder $query, array $values) 
    { 
     // Essentially we will force every insert to be treated as a batch insert which 
     // simply makes creating the SQL easier for us since we can utilize the same 
     // basic routine regardless of an amount of records given to us to insert. 
     $table = $this->wrapTable($query->from); 

     if (! is_array(reset($values))) { 
      $values = [$values]; 
     } 

     $columns = $this->columnize(array_keys(reset($values))); 

     // We need to build a list of parameter place-holders of values that are bound 
     // to the query. Each insert should have the exact same amount of parameter 
     // bindings so we will loop through the record and parameterize them all. 
     $parameters = collect($values)->map(function ($record) { 
      return '('.$this->parameterize($record).')'; 
     })->implode(', '); 

     return "insert ignore into $table ($columns) values $parameters"; 
    } 
} 

he copiado el método compileInsert de la clase del marco y luego, dentro del método, que sólo han cambiado insert-insert ignore. Todo lo demás se ha mantenido igual.

Luego, en el punto de código específica, en la aplicación (una tarea programada), en el que necesitaba "Insertar ignorar", simplemente he hecho de la siguiente manera:

<?php 

use DB; 
use My\Namespace\CustomMySqlGrammar; 

class SomeClass 
{ 
    public function someMethod() 
    { 
     // Changes "INSERT" to "INSERT IGNORE" 
     DB::connection()->setQueryGrammar(new CustomMySqlGrammar()); 

     // et cetera... for example: 
     ModelClass::insert($data); 
    } 
} 
Cuestiones relacionadas