CONSOLAIN在Laravel 5 Schema Builder上独一无二

时间:2015-07-03 01:35:22

标签: php laravel orm laravel-5 eloquent

首先,我想告诉你,我已经在互联网上搜索了这个问题,但我无法解决这个问题。

我的问题在于表格的主键。

我有2个表,事件 event_guest

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

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

每个活动都有很多event_guest,但每个活动的电子邮件在每个活动中都必须是唯一的。

在我的控制器上,我想通过在EventGuest模型上使用firstOrCreate方法获取或创建:

EventGuests::firstOrCreate(['eventid' => $eventid,'firstname' => 'Ivan', 'lastname'=>'Bravo', 'email'=>'ivnbrv@mac.com');

如果未在事件中设置电子邮件,则必须记录该条目。

+-----------+----------+-----------+-----------+----------------+
|  guestid  | eventid  | firstname | lastname | email           | 
+-----------+----------+-----------+-----------+----------------+
|         1 |        1 | Ivan      | Bravo     | ivnbrv@mac.com | 
+-----------+----------+-----------+-----------+----------------+

我需要的是eventid作为主键,guestid作为auto_increment字段,因此它可以在每个事件中重置为1。例如:

+-----------+----------+-----------+-----------+----------------+
|  guestid  | eventid  | firstname | lastname | email           | 
+-----------+----------+-----------+-----------+----------------+
|         1 |        1 | Ivan      | Bravo     | ivnbrv@mac.com | 
|         2 |        1 | John      | Doe       | test@mac.com   | 
|         1 |        2 | Ivan      | Bravo     | ivnbrv@mac.com | 
+-----------+----------+-----------+-----------+----------------+

并且我还需要电子邮件作为唯一字段以防止重复行。

目前我正在使用Laravel 5迁移,但是当我尝试重置主要字段时,它会提示此错误:

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

这是我的迁移代码:

    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'));

            });

我真的需要帮助才能正确理解这一点。

我过去没有遇到过麻烦:

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

现在

2 个答案:

答案 0 :(得分:3)

我理解你的要求。但我认为您在数据库中创建了太多冗余。你的情况要警惕Event和Guest之间的许多关系。我相信,会在很大程度上简化你的问题。所以我提出了一个与你所要求的不同的解决方案。

在您的问题中,Event可以有多个Guest,而Guest可以属于许多Event。我们可以在Laravel 5. *中提出这个,如下所示,

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');
    }

}

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');
    }

} 

迁移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');
});

现在订阅GuestEvent就像下面一样简单

$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

在这种方法中,您可以将eventguest数据分离到专用表中而不会重复,并且可以非常轻松地维护唯一性约束。你呢 创建数据透视表以维护他们的关系。

Read More关于Laravel Relationships。

答案 1 :(得分:2)

迁移代码存在两个问题,导致您无法创建所需的表格。

首先,默认的MySQL引擎是InnoDB,它不允许在复合主键上自动增加。因此,您需要将引擎显式设置为MyISAM:

$table->engine = 'MyISAM';

其次,当您将列设置为自动递增时,Laravel的架构构建器会假定它是主键,并在生成create语句时将该列作为主键。因此,当下一个查询尝试定义复合主键时,guestid列上已存在主键 - 因此存在重复的主键错误。

该问题的解决方案是将guestid定义为标准整数列,创建复合键,然后更新guestid列以使其自动增量。遗憾的是,架构构建器不支持除重命名列之外的任何更改操作,因此您需要使用基础数据库层并执行原始查询。

总而言之,您的迁移代码应如下所示:

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');