简体   繁体   English

在Laravel 5中使用UUID作为主键

[英]Using a UUID as primary key with Laravel 5

I'm trying to create tables that will have a primary key which is a UUID defined as binary(16) instead of the default auto-incrementing id field. 我正在尝试创建具有主键的表,该主键是定义为binary(16)的UUID,而不是默认的自动递增id字段。

I've managed to create migrations using raw SQL statements though DB::statement like so: 我设法使用原始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;");

However, I have trouble getting the model working. 但是,我无法让模型正常工作。 I've followed the tutorial available here . 我按照这里提供的教程进行了操作 I've defined my model like so: 我已经定义了我的模型:

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

where Uuid is an alias to Webpatser\\Uuid . 其中UuidWebpatser\\Uuid的别名。

One problem, I'm having is I cannot derive UuidModel from Eloquent as explained in the tutorial. 一个问题,我有是我不能获得UuidModelEloquent作为教程解释。 In fact I don't see an Eloquent class. 事实上,我没有看到一个Eloquent课程。 I'm deriving from Model instead. 我是从Model衍生出来的。 I am guessing the tutorial was written in Laravel 4. 我猜这个教程是用Laravel 4编写的。

I would appreciate help in implementing tables with UUIDs as primary keys in Laravel 5. 我很感激帮助实现将UUID作为Laravel 5主键的表。

EDIT 1: So, if I define my class like so: 编辑1:所以,如果我这样定义我的类:

use Illuminate\Database\Eloquent
class UuidModel extends Eloquent { ... }

I get the following error: 我收到以下错误:

PHP Fatal error:  Class 'Illuminate\Database\Eloquent' not found in /home/vagrant/transactly/app/UuidModel.php on line 8

If I remove the use Illuminate\\Database\\Eloquent line, I get the following error: 如果我删除use Illuminate\\Database\\Eloquent行,我会收到以下错误:

PHP Fatal error:  Class 'App\Eloquent' not found in /home/vagrant/transactly/app/UuidModel.php on line 8

Edit 2: I have discovered that the static::creating event is never called for when instances of UuidModel are created. 编辑2:我发现在static::creating UuidModel实例时永远不会调用static::creating事件。

I tried setting up the creating event listener in AppServiceProvider but that's not being called as well. 我尝试在AppServiceProvider设置creating事件监听器,但是也没有调用它。 Interestingly, the creating event is not called for a regular Laravel generated model User either. 有趣的是, 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(){}

}

So, I got the thing working like a charm (not tested unit testing): 所以,我得到的东西就像一个魅力(没有经过测试的单元测试):

  1. class UuidModel extends Eloquent is an older (Laravel 4) construct. class UuidModel extends Eloquent是一个较旧的(Laravel 4)构造。 We use class UuidModel extends Model in Laravel 5 我们在Laravel 5中使用class UuidModel extends Model
  2. The solution was to move the 解决方案是移动

     UuidModel::creating(function ($model) { echo "Creating Uuid Model...\\n"; $model->{$model->getKeyName()} = (string)$model->generateNewId(); }); 

    from AppServiceProvider::boot() to EventServiceProvider::boot() . AppServiceProvider::boot()EventServiceProvider::boot() No other changes were required. 无需其他更改。 Everything worked as expected. 一切都按预期工作。

I still don't know why (2) works in EventServiceProvider and not in AppServiceProvider as explained in the official docs . 我仍然不知道为什么(2)在EventServiceProvider工作,而不是在官方文档中解释的AppServiceProvider中。 But judging from the name, that's perhaps the way it was meant to be. 但从名称来看,这可能是它的意图。

How about this idea for storing a 36chr UUID as Binary(16) : 将36chr UUID存储为二进制(16)的想法怎么样:

IMO there is an advantage in not having Laravel generating the UUID . IMO 在没有Laravel生成UUID方面有一个优势 Namely, if new records (some day in the future) get inserted into the database from outside the application the UUID field is properly populated. 也就是说,如果新记录(将来的某一天)从应用程序外部插入到数据库中,则可以正确填充UUID字段。

My suggestion: Create a UUID default value trigger using migrations 我的建议:使用迁移创建UUID默认值触发器

(this trigger makes the DataBase server do the work to generate the UUID each time a new customer is inserted) (此触发器使DataBase服务器完成每次插入新客户时生成UUID的工作)

<?php namespace MegaBank\HighInterestLoans\Updates;
    use Illuminate\Database\Schema\Blueprint;
    use Illuminate\Database\Migrations\Migration;

class MigrationTriggerForCustomers extends Migration
{
public function up()
    {

        DB::unprepared('CREATE TRIGGER before_insert_customers
                      BEFORE INSERT ON    
                    `megabank_highinterestloans_customers` 
                      FOR EACH ROW
                      SET new.uuid = UNHEX(REPLACE(UUID(), "-","");');
    }

    public function down()
    {
        DB::unprepared('DROP TRIGGER `before_insert_customers`');
    }
}

Finally, if you want to get a human-readable version of your UUID just do the following: 最后,如果您想获得UUID的人类可读版本,请执行以下操作:

SELECT HEX(UUID) FROM customers;

Anyway, hope this helps someone :-) 无论如何,希望这有助于某人:-)

This is a quick solution without using events. 这是一种不使用事件的快速解决方案。

UUidModel.php 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
        }
    }
?>

Model Example Car.php 模型示例Car.php

<?php namespace App;

    class Car extends UuidModel {
    }

also try use this package will automatically generate and assign UUID field in your model, also can show and update by UUIDs key. 也尝试使用此包将自动生成并在您的模型中分配UUID字段,也可以通过UUIDs键显示和更新。

https://github.com/EmadAdly/laravel-uuid https://github.com/EmadAdly/laravel-uuid

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM