<p>This should be fixed in the next (<a href="https://craftcms.com/changelog#build2791" rel="nofollow">post 2.6.2791</a>) release so that plugins can define composite primary keys in their records.</p>

CC BY-SA 3.0
2016-06-21T07:57:57.837Z
You boys don't mess around do you! Thanks for the quick turnaround on this, it's much appreciated.
Steve Holland
CC BY-SA 3.0
2016-06-21T03:50:46.277Z
2016-06-21T03:50:46.277Z
Brad Bell
<p>It would appear not unfortunately.</p>

<p>Craft's <code>BaseRecord</code> (which a <code>Record</code> should inherit from) tries to uses the <code>primaryKey()</code> method call to help create the table, but assumes a single column name is returned, not an Array and so falls over on the <code>isset</code> call.</p>

<pre><code>$pk = $this-&gt;primaryKey();

if (isset($columns[$pk]))
{
  $columns[$pk]['primaryKey'] = true;
  $addIdColumn = false;
}
else
{
  $addIdColumn = true;
}
</code></pre>

<p>I'm guessing it should work because the <code>CActiveRecord</code> (which the <code>BaseRecord</code> inherits from) states in it's comments for PrimaryKey:</p>

<pre><code>@return mixed the primary key of the associated database table.

If the key is a composite one consisting of several columns, it should
return the array of the key column names.
</code></pre>

<p>EDIT: In the end I added the following to my Plugin file, and that seemed to do the trick:</p>

<pre><code>public function onAfterInstall()
{
  craft()-&gt;db-&gt;createCommand()-&gt;dropColumn('myplugin_merchant_order', 'id');
  craft()-&gt;db-&gt;createCommand()-&gt;addPrimaryKey('myplugin_merchant_order', ['merchant_id', 'order_id']);
}
</code></pre>

<p>I also had to add this to my Record, to stop the validation failing because I'd removed the <code>id</code> column in the above step:</p>

<pre><code>public function primaryKey()
{
    return null;
}
</code></pre>

CC BY-SA 3.0
2016-06-16T19:03:33.000Z
Yeah, I'd consider that a bug since it works in Yii (see here http://www.yiiframework.com/doc/guide/1.1/en/database.ar#defining-ar-class).  Will look into fixing it.
Brad Bell
CC BY-SA 3.0
2016-06-16T16:07:21.037Z
2016-06-17T12:38:20.643Z
2016-06-17T12:38:20.643Z
Steve Holland
<p>I've structured my Record as such:</p>

<pre><code>&lt;?php
namespace Craft;

class MyPlugin_MerchantOrderRecord extends BaseRecord
{
  public function getTableName()
  {
    return 'myplugin_merchant_orders';
  }

  protected function defineAttributes()
  {
    return [
      'merchant_id' =&gt; AttributeType::Number,
      'order_id' =&gt; AttributeType::Number,
      ...
    ];
  }

  public function primaryKey()
  {
    return ['merchant_id', 'order_id'];
  }

  public function defineRelations()
  {
      return [
        'merchant' =&gt; [static::BELONGS_TO, 'MyPlugin_MerchantRecord', 'merchant_id', 
               'required' =&gt; true, 'onDelete' =&gt; static::CASCADE],
        'order' =&gt; [static::BELONGS_TO, 'Commerce_OrderRecord', 'order_id', 
               'required' =&gt; true, 'onDelete' =&gt; static::CASCADE],
      ];
  }
}
</code></pre>

<p>When I install the plugin I get the following error:</p>

<p><code>Illegal offset type in isset or empty</code></p>

<p>If I take away the <code>primaryKey()</code> definition, the table is created successfully and the <code>foreign keys</code> are in place as expected.</p>

<p>Any help gratefully received.</p>

<plugin-development><database><records>
Is it possible to create composite Primary Keys in Records?
# Is it possible to create composite Primary Keys in Records?

(Asked by: username_0 on 2016-06-16)

I've structured my Record as such:
 AttributeType::Number,
      'order_id' => AttributeType::Number,
      ...
    ];
  }

  public function primaryKey()
  {
    return ['merchant_id', 'order_id'];
  }

  public function defineRelations()
  {
      return [
        'merchant' => [static::BELONGS_TO, 'MyPlugin_MerchantRecord', 'merchant_id', 
               'required' => true, 'onDelete' => static::CASCADE],
        'order' => [static::BELONGS_TO, 'Commerce_OrderRecord', 'order_id', 
               'required' => true, 'onDelete' => static::CASCADE],
      ];
  }
}

When I install the plugin I get the following error:
Illegal offset type in isset or empty
If I take away the primaryKey() definition, the table is created successfully and the foreign keys are in place as expected.
Any help gratefully received.

**Tags:** plugin-development, database, records

---

## 2 answers

### Answer by username_1 on 2016-06-21. Score: 2 | Accepted answer

This should be fixed in the next ([post 2.6.2791](https://craftcms.com/changelog#build2791)) release so that plugins can define composite primary keys in their records.

> **Comments:**
> **username_0**: You boys don't mess around do you! Thanks for the quick turnaround on this, it's much appreciated.  

---

### Answer by username_0 on 2016-06-16. Score: 2

It would appear not unfortunately.
Craft's BaseRecord (which a Record should inherit from) tries to uses the primaryKey() method call to help create the table, but assumes a single column name is returned, not an Array and so falls over on the isset call.
$pk = $this->primaryKey();

if (isset($columns[$pk]))
{
  $columns[$pk]['primaryKey'] = true;
  $addIdColumn = false;
}
else
{
  $addIdColumn = true;
}

I'm guessing it should work because the CActiveRecord (which the BaseRecord inherits from) states in it's comments for PrimaryKey:
@return mixed the primary key of the associated database table.

If the key is a composite one consisting of several columns, it should
return the array of the key column names.

EDIT: In the end I added the following to my Plugin file, and that seemed to do the trick:
public function onAfterInstall()
{
  craft()->db->createCommand()->dropColumn('myplugin_merchant_order', 'id');
  craft()->db->createCommand()->addPrimaryKey('myplugin_merchant_order', ['merchant_id', 'order_id']);
}

I also had to add this to my Record, to stop the validation failing because I'd removed the id column in the above step:
public function primaryKey()
{
    return null;
}

> **Comments:**
> **username_1**: Yeah, I'd consider that a bug since it works in Yii (see here http://www.yiiframework.com/doc/guide/1.1/en/database.ar#defining-ar-class).  Will look into fixing it.  

---

