2015-07-03 11 views
5

Prima di tutto, voglio dirvi che ho cercato su Internet questo problema e non sono stato in grado di risolvere questo problema.CONSTRAIN Unico su Laravel 5 Schema Builder

Il mio problema è con le chiavi primarie dei miei tavoli.

Ho 2 tabelle, eventi e event_guest

+-----------+ 
| event  | 
+-----------+ 
| eventid | 
+-----------+ 

+-------------+ 
| event_guest | 
+-------------+ 
| guestid  | 
| eventid  | 
| firstname | 
| lastname | 
| email  | 
+-------------+ 

Ogni evento ha molti event_guest, ma l'e-mail di ogni ospite deve essere unico per ogni evento.

Il mio controller voglio ottenere o creare utilizzando il metodo firstOrCreate su EventGuest Modello:

EventGuests::firstOrCreate(['eventid' => $eventid,'firstname' => 'Ivan', 'lastname'=>'Bravo', 'email'=>'[email protected]'); 

Se l'email non è impostata sul caso si deve registrare la voce.

+-----------+----------+-----------+-----------+----------------+ 
| guestid | eventid | firstname | lastname | email   | 
+-----------+----------+-----------+-----------+----------------+ 
|   1 |  1 | Ivan  | Bravo  | [email protected] | 
+-----------+----------+-----------+-----------+----------------+ 

quello che mi serve è eventid come chiave primaria e guestid come auto_increment campo in modo che possa ripristinare a 1 per ogni evento. Ad esempio:

+-----------+----------+-----------+-----------+----------------+ 
| guestid | eventid | firstname | lastname | email   | 
+-----------+----------+-----------+-----------+----------------+ 
|   1 |  1 | Ivan  | Bravo  | [email protected] | 
|   2 |  1 | John  | Doe  | [email protected] | 
|   1 |  2 | Ivan  | Bravo  | [email protected] | 
+-----------+----------+-----------+-----------+----------------+ 

E inoltre ho bisogno di e-mail come un campo unico per evitare le righe duplicate.

Attualmente sto usando laravel 5 Migrazioni, ma quando provo a ripristinare campi primari viene richiesto questo errore:

Multiple primary key defined (SQL: alter table `event_guest` add primary key event_guest_eventid_guestid_primary(`eventid`, `guestid`))        

Questo è il mio codice di migrazione:

Schema::create('event_guest', function(Blueprint $table) { 
       $table->integer('guestid', true); 
       $table->integer('eventid'); 
       $table->integer('contactid')->nullable(); 
       $table->string('firstname', 256); 
       $table->string('lastname', 256); 
       $table->string('email', 256); 
       $table->unique(array('email','name')); 
       $table->primary(array('eventid','guestid')); 

      }); 

ho davvero bisogno di aiuto per capirlo correttamente

non ho avuto difficoltà in passato utilizzando:

create table `event_guest` (
    `guestid` int(11) NOT NULL AUTO_INCREMENT, 
    `eventid` int(11) NOT NULL DEFAULT '0', 
    `firstname` varchar(255) NOT NULL, 
    `lastname` varchar(255) NOT NULL, 
    `email` varchar(255) NOT NULL, 
    PRIMARY KEY (`eventid`,`guestid`), 
    CONSTRAINT guest UNIQUE (eventid,email) 
) ENGINE=MyISAM 

Ora

+1

Sarebbe possibile suddividere l'ID ospite, il nome, il cognome e l'e-mail nella propria tabella denominata "ospite". Quindi cambia lo schema di 'event_guest' in solo event_id e guest_id? –

risposta

2

Ci sono 2 problemi con il codice di migrazione che impediscono la creazione della tabella è necessario.

Prima di tutto, il motore MySQL predefinito è InnoDB, che non consente l'incremento automatico su chiavi primarie composite. Pertanto, è necessario impostare il motore in modo esplicito per MyISAM:

$table->engine = 'MyISAM'; 

In secondo luogo, quando si imposta una colonna a incremento automatico, generatore di schemi di laravel presuppone che è la chiave primaria e fa quella colonna una chiave primaria per la generazione creare dichiarazione . Pertanto, quando la query successiva tenta di definire la chiave primaria composta, esiste già la chiave primaria esistente nella colonna guestid, quindi l'errore della chiave primaria duplicata.

La soluzione a questo problema è definire guestid come colonna di interi standard, creare la chiave composita e quindi aggiornare la colonna guestid in modo che sia autoincrementata. Sfortunatamente lo schema builder non supporta alcuna operazione di modifica oltre alla ridenominazione della colonna, quindi è necessario utilizzare il livello DB sottostante ed eseguire una query non elaborata.

In sintesi, il codice di migrazione dovrebbe essere simile a questo:

Schema::create('event_guest', function(Blueprint $table) { 
    $table->engine = 'MyISAM'; 
    $table->integer('guestid'); 
    $table->integer('eventid'); 
    $table->integer('contactid')->nullable(); 
    $table->string('firstname', 256); 
    $table->string('lastname', 256); 
    $table->string('email', 256); 
    $table->unique(array('email','name')); 
    $table->primary(array('eventid','guestid')); 
}); 

DB::statement('ALTER TABLE event_guest MODIFY guestid INTEGER NOT NULL AUTO_INCREMENT'); 
+0

ho dovuto solo cambiare $ table-> unique (array ('email', 'name')); per $ table-> unique (array ('guestid', 'email')); ed ero a posto! ... –

3

Capisco quello che stai chiedendo. Ma penso che stai creando troppa ridondanza nel tuo database. La tua situazione metterà in relazione TanteMolte relazioni tra l'evento e l'ospite. Ciò che credo, semplificherà in larga misura il tuo problema. Quindi sto presentando una soluzione diversa da quello che stai chiedendo.

Nel vostro problema Event può avere molte Guest s, e Guest può appartenere a molte Event s. Siamo in grado di presentare questo in laravel 5. * come sotto,

Migrazione e modello per Event

Schema::create('events', function(Blueprint $table){ 
    $table->increments('id')->unsigned(); 
    $table->string('title'); 
    $table->string('venue'); 
    $table->text('description'); 
    $table->timestamps(); 
}); 

class Event extends Model{ 

    public function guests(){ 
     return $this->belongsToMany('App\Guest', 'event_guests'); 
    } 

} 

Migrazione e modello per Guest

Schema::create('guests', function(Blueprint $table){ 
    $table->increments('id')->unsigned(); 
    $table->string('email')->unique(); 
    $table->string('password'); 
    $table->string('first_name'); 
    $table->string('last_name'); 
    $table->timestamps(); 
}); 

class Guest extends Model{ 

    public function events(){ 
     return $this->belongsToMany('App\Event','event_guests'); 
    } 

} 

migrazione per event_guests

Schema::create('event_guests', function(Blueprint $table){ 
    $table->increments('id'); 
    $table->integer('event_id')->unsigned();  
    $table->integer('guest_id')->unsigned()->nullable(); 

    $table->foreign('guest_id')->references('id')->on('guests')->onDelete('cascade'); 
    $table->foreign('event_id')->references('id')->on('events')->onDelete('cascade'); 
}); 

Ora la sottoscrizione Guest a Event è facile come di seguito

$event = Event::create([ 
      'title' => 'Laracon', 
      'venue' => 'Hotel XYZ, New York', 
      'description' => 'Drink is not free' 
     ]); 
$guest = Guest::findOrFail($guestId); 
$guest2 = Guest::findOrFail($guestId2); 

$event->guests()->sync([$guestId->id, $guestId2->id], false); //`false` as second argument prevents `sync` from detaching previous associations 

In questo stetagy, è possibile separare event e guest dati alle tabelle dedicate senza duplicazioni e mantenere vincoli di unicità molto facilmente. E tu crea la tabella pivot per mantenere le loro relazioni di spedizione.

Read More sulle relazioni Laravel.

+0

Grazie mille per la tua risposta, ho iniziato questo progetto in questo modo, creando tabelle separate e creando relazioni, è molto logico e ben scritto. Il problema con i vincoli nella mia applicazione è che, in passato mi è stato chiesto di considerare anche gli utenti registrati, di far parte degli ospiti dell'evento ... quindi, i problemi sono iniziati quando ho migrato l'app a laravel, per mantenere la struttura db e dati, ho dovuto creare le migrazioni come loro in cui nell'altro database. +1 Consiglierei il tuo approccio ad altri utenti e best practice, ma il suggerimento di jedrzej.kurylo ha funzionato per me in questo caso! –