web-dev-qa-db-fra.com

Comment puis-je mettre des clés composites dans des modèles dans Laravel 5?

J'ai dans ma base de données une table avec deux clés primaires (id et language_id) et je dois la mettre dans mes modèles. PrimaryKey par défaut dans Models (Model.php dans Laravel 5) est id et je souhaite que les primaryKeys soient id et id_language. J'ai essayé de le mettre avec des tableaux ou une chaîne avec ',' mais cela ne fonctionne pas. Il me dit que le tableau n'a pas pu être converti en chaîne.

S'il vous plaît aider.

Merci!

33
Sergioh Lonet

Tu ne peux pas. Eloquent ne supporte pas les clés primaires composites.

Voici un problème de Github à ce sujet.

26
lukasgeiter

J'ai écrit ce trait simple PHP pour adapter Eloquent à la gestion des clés composites:

<?php

namespace App\Model\Traits; // *** Adjust this to match your model namespace! ***

use Illuminate\Database\Eloquent\Builder;

trait HasCompositePrimaryKey
{
    /**
     * Get the value indicating whether the IDs are incrementing.
     *
     * @return bool
     */
    public function getIncrementing()
    {
        return false;
    }

    /**
     * Set the keys for a save update query.
     *
     * @param  \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    protected function setKeysForSaveQuery(Builder $query)
    {
        foreach ($this->getKeyName() as $key) {
            // UPDATE: Added isset() per devflow's comment.
            if (isset($this->$key))
                $query->where($key, '=', $this->$key);
            else
                throw new Exception(__METHOD__ . 'Missing part of the primary key: ' . $key);
        }

        return $query;
    }

    // UPDATE: From jessedp. See his edit, below.
    /**
     * Execute a query for a single record by ID.
     *
     * @param  array  $ids Array of keys, like [column => value].
     * @param  array  $columns
     * @return mixed|static
     */
    public static function find($ids, $columns = ['*'])
    {
        $me = new self;
        $query = $me->newQuery();
        foreach ($me->getKeyName() as $key) {
            $query->where($key, '=', $ids[$key]);
        }
        return $query->first($columns);
    }
}

Placez-le dans un répertoire Traits sous votre répertoire de modèle principal, puis vous pouvez ajouter une simple ligne à la première place de tout modèle de clé composite:

class MyModel extends Eloquent {
    use Traits\HasCompositePrimaryKey; // *** THIS!!! ***

    /**
     * The primary key of the table.
     * 
     * @var string
     */
    protected $primaryKey = array('key1', 'key2');

    ...


ajouté par jessedp:
Cela a fonctionné à merveille jusqu'à ce que je veuille utiliser Model :: find ... voici donc du code (qui pourrait probablement être meilleur) qui peut être ajouté au trait hasCompositePrimaryKey ci-dessus: 

protected static function find($id, $columns = ['*'])
{
    $me = new self;
    $query = $me->newQuery();
    $i=0;

    foreach ($me->getKeyName() as $key) {
        $query->where($key, '=', $id[$i]);
        $i++;
    }

    return $query->first($columns);
}

Mise à jour 2016-11-17

Je maintiens maintenant cela dans le cadre d'un paquet open-source appelé LaravelTreats .

64
mopo922

Il semble que cela ait changé, puisque celui-ci fonctionne avec au moins Laravel 5.1:

$table->primary(['key1', 'key2']);

Je viens d'exécuter la migration et ce que je vois dans la base de données correspond à ce que j'ai mis dans le code ci-dessus (bien sûr, les champs de nom ci-dessus sont juste à des fins de présentation).

Update: cela est vrai pour les migrations, mais dès que vous voulez insérer via eloquent, cela ne fonctionne pas avec les clés composites et ne le fera jamais (dernière entrée):

https://github.com/laravel/framework/issues/5517

12
sba

Dans les migrations vous pouvez simplement définir les clés primaires composites d'une table sous la forme @ erick-suarez et @sba, dans votre bloc Schema::create ou Schema::table, écrivez $table->primary(['key1', 'key2']);

Dans le modèle Eloquent qui représente cette table, vous ne pouvez pas utiliser directement cette clé composite avec les méthodes Eloquent, par ex. find($key) ni save($data) mais vous pouvez toujours récupérer l'instance de modèle à des fins d'affichage à l'aide de

$modelObject = ModelName->where(['key1' => $key1, 'key2' => $key2])->first();

Et si vous souhaitez mettre à jour un enregistrement dans cette table, vous pouvez utiliser les méthodes QueryBuilder comme ceci:

ModelName->where(['key1' => $key1, 'key2' => $key2])->update($data);

$data est le tableau associatif de données avec lequel vous souhaitez mettre à jour votre modèle, alors so ['attribute1' => 'value1', ..].


Remarque: Vous pouvez toujours utiliser les relations Eloquent en toute sécurité pour les récupérer avec ces modèles, car elles sont couramment utilisées en tant que tableaux croisés dynamiques rompant les structures de relation plusieurs à plusieurs.

5

https://laravel.com/docs/5.3/migrations#columns

Oui tu peux.

je partage mon code de migration:

    <?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class RegistroEmpresa extends Migration {

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('registro_empresa', function(Blueprint $table)
        {
            $table->string('licencia',24);
            $table->string('rut',12);
            $table->string('nombre_empresa');
            $table->string('direccion');
            $table->string('comuna_Estado');
            $table->string('ciudad');
            $table->string('pais');
            $table->string('fono');
            $table->string('email');
            $table->string('paginaweb');
            $table->string('descripcion_tienda');
            $table->string('monedauso');
            $table->timestamps();
            $table->primary(['licencia', 'rut']);
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('registro_empresa');
    }

}
2
Erick Suarez

Essayez de regarder cette documentation pour insérer plusieurs relations avec CK.

https://laravel.com/docs/5.2/eloquent-relationships#inserting-many-to-many-relationships

Edit: quelques infos supplémentaires 
Comme vous pouvez le constater dans la documentation, les fonctions d'attachement et de détachement créent les liens nécessaires dans la table intermédiaire CK. Donc vous n'avez pas à les créer vous-même;)

Dans votre cas, ce serait model->languages()->attach(language_id)

1
Reyske

Veuillez visiter ces deux liens ci-dessous, ces solutions ont résolu mon problème de clé primaire composite ou multi-colonne - 

  1. Création d'une base de données avec des clés composites

  2. Erreur de type de décalage illégale

0
Sadidul Islam

Voici mon fichier de migration, cela a résolu mon problème de gestion des clés dans la migration .. Vous aurez peut-être besoin de mettre à jour la classe de modèle ultérieurement, si vous obtenez une erreur de type offset illégale ou quelque chose du genre. La solution est ici - ici

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateAccountSessionsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('account_sessions', function (Blueprint $table) {
            $table->string('session', 64);//creates a string column, that can use in primary key. don't let it exceeds 797 bytes
            $table->integer('account_id')->unsigned();//unsigned integer column
            $table->timestamps();

            $table->primary(['session', 'account_id']);//added the primary keys

            $table->foreign('account_id')->references('id')->on('accounts');//foreign key
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('account_sessions');
    }
}
0
Sadidul Islam

vous pouvez essayer d'utiliser le module suivant 

https://github.com/maksimru/composite-primary-keys

ajoutez simplement le trait HasCompositePrimaryKey à votre modèle et spécifiez la valeur du tableau comme clé primaire

0
Maksim Martianov

J'espère que ça aide 

Schema::create('vw_term_relationships', function (Blueprint $table) {
            $table->bigInteger('object_id')->unsigned()->default('0');
            $table->bigInteger('term_taxonomy_id')->unique()->unsigned()->default('0');
            $table->integer('term_order')->default('0');
            $table->primary(['object_id', 'term_taxonomy_id']);
        });

 enter image description here

0
ViperTecPro