Php 使用UUID作为Laravel 5的主键

Php 使用UUID作为Laravel 5的主键,php,mysql,laravel,laravel-5,eloquent,Php,Mysql,Laravel,Laravel 5,Eloquent,我正在尝试创建具有主键的表,主键是定义为binary(16)的UUID,而不是默认的自动递增id字段 我已经成功地使用原始SQL语句创建了迁移,尽管DB::statement类似这样: DB::statement("CREATE TABLE `binary_primary_keys` ( `uuid` binary(16) NOT NULL DEFAULT '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0',

我正在尝试创建具有主键的表,主键是定义为
binary(16)
的UUID,而不是默认的自动递增
id
字段

我已经成功地使用原始SQL语句创建了迁移,尽管
DB::statement
类似这样:

DB::statement("CREATE TABLE `binary_primary_keys` (
                      `uuid` binary(16) NOT NULL DEFAULT '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0',
                      `created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
                      `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
                      PRIMARY KEY (`uuid`)
                  ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;");
但是,我很难让模型正常工作。我遵循了可用的教程。我这样定义了我的模型:

class UuidModel extends Model
{
    public $incrementing = false;
    public $primaryKey = 'uuid';

    /**
     * The "booting" method of the model.
     *
     * @return void
     */
    protected static function boot()
    {
        parent::boot();

        /**
         * Attach to the 'creating' Model Event to provide a UUID
         * for the `id` field (provided by $model->getKeyName())
         */
        static::creating(function ($model) {
            $model->{$model->getKeyName()} = (string)$model->generateNewId();
            echo($model->{$model->getKeyName()});
        });
    }

    /**
     * Get a new version 4 (random) UUID.
     */
    public function generateNewId()
    {
        return Uuid::generate();
    }
}
其中
Uuid
webpacser\Uuid
的别名

我遇到的一个问题是,我无法从
雄辩的
中导出
UuidModel
,如教程中所述。事实上,我没有看到一个有口才的班。我是从
模型
衍生出来的。我猜教程是用拉维4写的

如果能在Laravel5中帮助实现UUID作为主键的表,我将不胜感激

编辑1: 因此,如果我这样定义我的类:

use Illuminate\Database\Eloquent
class UuidModel extends Eloquent { ... }
我得到以下错误:

PHP Fatal error:  Class 'Illuminate\Database\Eloquent' not found in /home/vagrant/transactly/app/UuidModel.php on line 8
PHP Fatal error:  Class 'App\Eloquent' not found in /home/vagrant/transactly/app/UuidModel.php on line 8
如果删除
use illumb\Database\elount
行,则会出现以下错误:

PHP Fatal error:  Class 'Illuminate\Database\Eloquent' not found in /home/vagrant/transactly/app/UuidModel.php on line 8
PHP Fatal error:  Class 'App\Eloquent' not found in /home/vagrant/transactly/app/UuidModel.php on line 8
编辑2: 我发现在创建
UuidModel
的实例时,从未调用
static::creating
事件

我尝试在
AppServiceProvider
中设置
创建
事件侦听器,但也没有调用它。有趣的是,
creating
事件也不是为常规的Laravel生成的模型
User
调用的

class AppServiceProvider extends ServiceProvider
{
/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    /**
     * Attach to the 'creating' Model Event to provide a UUID
     * for the `id` field (provided by $model->getKeyName())
     */
    echo "Booting...\n";
    UuidModel::creating(function ($model) {
        echo "Creating Uuid Model...\n";
        $model->{$model->getKeyName()} = (string)$model->generateNewId();
    });

    User::creating(function($user){
        echo "Creating User Model...";
        $user->name = 'Forced Name in boot()';
    });
}
public function register(){}

}

这是一个不使用事件的快速解决方案

UUidModel.php

<?php        namespace App;

    use \Illuminate\Database\Eloquent\Model;

    use \Illuminate\Database\Eloquent\Builder;

    class UuidModel extends Model

    {

    /**

    * Insert the given attributes and set the ID on the model.

    *

    * @param  \Illuminate\Database\Eloquent\Builder  $query

    * @param  array  $attributes

    * @return void

    */

        protected function insertAndSetId(Builder $query, $attributes)

        {
            $keyName = $this->getKeyName();
            $id = $attributes[$keyName] = $this->generateNewId();
            $query->insert($attributes);
            $this->setAttribute($keyName, $id);
        }

    /**
    * Get a new version 4 (random) UUID.
    */
        public function generateNewId()
        {
            return 'uuid!!' ;// just for test
        }
    }
?>

模型示例Car.php

<?php namespace App;

    class Car extends UuidModel {
    }

因此,我让它像一个魔咒一样工作(未经测试的单元测试):

  • 类UuidModel扩展了雄辩的
    是一个较老的(Laravel 4)构造。我们在Laravel 5中使用
    类UuidModel扩展模型
  • 解决的办法是移动

    UuidModel::creating(function ($model) {
        echo "Creating Uuid Model...\n";
        $model->{$model->getKeyName()} = (string)$model->generateNewId();
    });
    
    AppServiceProvider::boot()
    EventServiceProvider::boot()
    。无需进行其他更改。一切如期进行


  • 我仍然不知道为什么(2)在
    EventServiceProvider
    中起作用,而在
    AppServiceProvider
    中不起作用,正如官方解释的那样。但从名字来看,这可能就是它的本意

    将36chr UUID存储为二进制(16)的想法如何:

    在IMO中,没有Laravel生成UUID有一个优势。也就是说,如果新记录(将来某一天)从应用程序外部插入到数据库中,UUID字段将正确填充

    我的建议是:使用迁移创建UUID默认值触发器 (此触发器使数据库服务器在每次插入新客户时生成UUID)


    无论如何,希望这对某人有所帮助:-)

    也尝试使用此软件包将自动生成和分配模型中的UUID字段,还可以通过UUID键显示和更新


    您是否尝试使用字符(36)标识?不,我没有。我想char(36)的效率会低一些。我真的不知道,但我认为比较二进制文件在比较中没有相同的精度,如果你使用,你应该转换成二进制文件,对吗?我认为,在位级别上,二进制(16)只是一个数字,仅比常规int(4)大四倍,本文会有所帮助。整数比较总是比字符(36)比较快。你指给我看的那篇文章证明了比较是缓慢的。如果我冒昧猜测一下,我会说作者看到了减速,因为他使用了char(36)列作为pk而不是binary(16)。那么你是说你得到了一个错误,
    elount
    类没有找到?如果是这样的话,请公布您得到的确切错误。我尝试了这种方法,但从未调用中的
    insertAndSetId
    函数。实际上,我可以在基类的实现中看到,只有当
    $this->incrementing
    true
    时,才会调用
    insertAndSetId
    。在我的例子中,由于
    uuid
    列不是递增的,所以我将
    $this->incrementing
    设置为
    false
    。使用这种方式,递增属性必须为true(默认值),只需查看汽车模型我将使用trait,而不是创建扩展基本
    模型的“uuid model”类。这样,您就可以添加和删除UUID功能,而无需更改它扩展的类。还有,我不知道你为什么在迁移中使用原始SQL?@MartinBean是的,现在我已经让它工作了,我将尝试traits。谢谢你的提示。我使用原始sql,因为AFAIK、SchemaBuilder不支持二进制列。我的UUID列是二进制的(16),以获得最大的效率。:在子标题“Available Column Types”下,您可以找到二进制的。@MartinBean我看到了,但这映射到了没有指定长度的BLOB类型。我不完全确定BLOB是否会像二进制(16)那样高效,二进制(16)基本上比INT大4倍。我相信MySQL不会在同一个表中存储BLOB值。为了使模型使用uuid而不是自动递增,我做了一个简单的特性。你可以在。它变得尽可能简单,因为测试很多选项会减慢已经很慢的进程:)。