Knex: Tidak dapat membuat beberapa PK (mixin .increments dengan .primary)

Dibuat pada 18 Jul 2014  ·  31Komentar  ·  Sumber: knex/knex

Saya ingin membuat tabel berdasarkan dump MySQL berikut:

CREATE TABLE `my_table` (
  `cmdId` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `deviceId` char(16) NOT NULL,
  `fnNumber` int(10) unsigned DEFAULT NULL,
  `chNumber` int(10) unsigned DEFAULT NULL,
  `cmd` varchar(50) DEFAULT NULL,
  `cmdDate` datetime DEFAULT NULL,
  `delivered` tinyint(1) DEFAULT NULL,
  PRIMARY KEY (`cmdId`,`deviceId`),
  KEY `deviceId` (`deviceId`),
  CONSTRAINT `tblcommands_ibfk_1` FOREIGN KEY (`deviceId`) REFERENCES `second_table` (`deviceId`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Knex saya terlihat seperti:

knex.schema.createTable('my_table', function(t) {
    t.primary(['cmdId', 'deviceId']);
    t.increments('cmdId');
    t.string('deviceId', 16).notNullable().references('second_table.deviceId');
    t.integer('fnNumber').unsigned();
    t.integer('chNumber').unsigned();
    t.string('cmd96', 50);
    t.dateTime('cmdDate');
    t.boolean('delivered');
});

Namun, ada masalah dengan kunci utama. Saya mendapatkan kesalahan berikut:

Error: Multiple primary key defined

Saya berasumsi bahwa metode increments sudah membuat PK dan metode primary membuat metode lain yang menyebabkan kesalahan.

Apakah mungkin untuk mencapai format tabel ini?

bug

Komentar yang paling membantu

Atau Anda dapat membuat kolom de autoincrement dengan

table.specificType('myid','serial');

(hanya untuk Postgresql)

Tapi saya pikir jauh lebih baik table.increments() akan membuat PK hanya jika saya menentukannya secara manual dengan table.increments().primary()

Semua 31 komentar

Tidak, tapi mungkin seharusnya begitu. Saya akan mencari sesuatu untuk ini.

Menurut https://github.com/tgriesser/knex/blob/master/lib/dialects/mysql/schema/column.js#L30

ColumnCompiler_MySQL.prototype.increments = 'int unsigned not null auto_increment primary key';

Jadi, .increments() membuat PK. Bukankah itu perilaku yang terlalu kuat? Menurut saya, akan lebih baik jika membuat kolom AUTO_INCREMENT tanpa PK, jadi:

int unsigned not null auto_increment

Dan untuk membuat PK, kita harus memanggil .primary() :

table.increments('id').primary();

Ini akan memungkinkan untuk membuat banyak PK dengan kolom AUTO_INCREMENT .

Sebagai workaroud yang saya gunakan sekarang:

table.primary(['cmdId', 'deviceId']);
table.integer('cmdId').notNullable();
table.string('deviceId', 16).notNullable().references('second_table.deviceId');

Dan di then callback:

knex.schema.raw('ALTER TABLE my_table MODIFY cmdId INT UNSIGNED AUTO_INCREMENT');

Saya memiliki masalah serupa - Saya ingin menggunakan .increments() tanpa itu menjadi kunci utama. Dalam kasus saya, ini karena alasan kinerja. Saya ingin membuat tabel tanpa indeks (yang berarti tanpa kunci utama), memasukkan banyak baris ke dalamnya, lalu menambahkan indeks pada kolom autoincrement. Ini lebih berkinerja, dan pada kenyataannya direkomendasikan oleh dokumentasi Postgres (lihat http://www.postgresql.org/docs/9.4/static/populate.html#POPULATE-RM-INDEXES), tetapi saat ini tampaknya tidak mungkin dilakukan dengan knex.

Saya juga sepertinya mengalami masalah serupa. Saya tidak dapat membuat tabel yang memiliki:

knex.schema.createTable("numeric_table", function (table) {
    table.integer("integer_key").primary;

   // Both increments & bigIncrements tries to create primary key.
    table.increments("increment_key");
    table.bigIncrements("big_increment_key");
});

Masalah yang sama di sini .increments () mencoba untuk mendefinisikan kunci utama, meskipun saya menentukannya secara manual

Anda dapat menggunakan kueri mentah untuk menambahkan kolom kenaikan tanpa kunci utamanya:

exports.up = function (knex) {
  return Promise.all([
    knex.raw('alter table "my_table" add column "my_seq" bigserial'),
  ]);
};

exports.down = (knex) => {
  return Promise.all([
    knex.schema.table('my_table', (t) => {
      t.dropColumn('my_seq');
    }),
  ]);
};

Atau Anda dapat membuat kolom de autoincrement dengan

table.specificType('myid','serial');

(hanya untuk Postgresql)

Tapi saya pikir jauh lebih baik table.increments() akan membuat PK hanya jika saya menentukannya secara manual dengan table.increments().primary()

Mengapa tidak pergi
increments: 'serial'
dari pada
increments: 'serial primary key'

Ada masalah apa dengan itu?

Saya tetap mengalami masalah yang sama.
IMHO .increments seharusnya tidak membuat PK.

Ada berita tentang masalah ini?

Setuju - meskipun mungkin untuk mengatasi masalah ini dengan berbagai cara, agak aneh bahwa API tidak memiliki dukungan kelas satu untuk membuat kolom kenaikan otomatis tanpa menjadikannya kunci utama.

Dengan itu, saya membayangkan ini belum diperbaiki karena untuk memperbaikinya dengan cara yang paling masuk akal akan menjadi perubahan yang menghancurkan, dan karenanya harus menjadi bagian dari benjolan versi utama.

@tokopedia
Masalahnya adalah jika kita menggunakan .primary() pada kolom saat membuat tabel, hasilnya akan menjadi kueri terpisah untuk membuat tabel, dan kueri alter table untuk menentukan kunci utama.
Saya pikir di MySQL (atau mungkin DBMS lain juga), Anda tidak dapat memiliki bidang auto_incremement tanpa PK.
Jadi, knex membuat tabel dengan kunci utama, dan kemudian tidak bisa hanya alter untuk mendefinisikan dua kunci utama karena tabel sudah memilikinya.
Jika kita bisa memperbaikinya, mungkin .increments masih membuat PK tetapi mengizinkan kolom lain untuk PK juga semua dalam satu create table query, jadi kita mungkin tidak memerlukan versi besar benjolan.

Atau kita dapat menambahkan tipe kolom lain untuk ini dan membiarkan .increments sebagaimana tidak merusak kompatibilitas ke belakang.

@ amir-s: baik itu menjelaskan mengapa knex berperilaku seperti itu - tampaknya mencoba untuk memiliki perilaku yang setara di berbagai DBMS yang didukung. Saya tidak terlalu suka itu, tapi setidaknya sekarang tidak terlihat aneh.

Masalah dengan saran Anda adalah bahwa menurut definisi Anda tidak dapat memiliki beberapa kunci utama di atas tabel. (Anda dapat memiliki 1 PK komposit pada beberapa kolom, tetapi itu sangat berbeda dengan memiliki 2 PK kolom tunggal.)

Jadi jika .increments membuat PK, maka tidak mungkin untuk mengizinkan kolom lain juga ditandai sebagai PK. Dimungkinkan untuk membuat opsi yang dapat diteruskan ke .increments untuk menonaktifkan perilaku kunci utama pada Postgres dan DBMS lain yang mendukung perilaku tersebut. Mungkin itu solusi terbaik, karena tidak merusak kompatibilitas ke belakang dan juga tidak merusak kompatibilitas lintas-DBMS. Saya masih tidak suka itu serta mengubah perilaku default pada Postgres sehingga .increments tidak juga menjadikannya PK, tetapi itu akan menjadi PR yang lebih mudah diterima.

Jika ada yang ingin mengirimkan PR seperti itu, saya akan membantahnya. :-)

@zacronos Maaf, dengan "beberapa PK" yang saya maksud adalah "satu PK di banyak kolom".

Setuju dengan semua komentar di atas. Perilaku ini tidak terduga saat mencoba membuat kunci utama komposit serta kolom penambahan otomatis bukan kunci. Akan sangat menyenangkan melihat ini diterapkan.

Saya mengalami masalah ini juga, tetapi dalam kasus menggunakan Postgres dan menggunakan bidang serial sebagai kunci asing - implementasi knex dari bidang serial Postgres adalah increments() dan ini menjadikannya kunci utama secara default. Saya ingin dapat membangun sqlite3 serta postgres, jadi menggunakan kueri knex mentah akan membatasi saya pada salah satu atau. Ada saran pemecahan masalah?

Utas ini tidak mendapat banyak perhatian selama beberapa waktu. Saya ingin mengulangi apa yang menurut saya merupakan solusi yang ideal dan kompatibel dengan versi sebelumnya (yang dapat menjadi bagian dari rilis minor apa pun): tambahkan opsi baru ke .increments() , mungkin primaryKey: false , yang mana (untuk DBMS jika memungkinkan) menonaktifkan bagian kunci utama dari fungsinya.

Ini sepenuhnya kompatibel ke belakang karena .increments() mempertahankan perilaku defaultnya.

@zacronos Melihat sekilas kode. Tampak sepele. Akan membuat PR
https://github.com/DeedMob/knex/tree/master/src

Masalah yang sama di sini. Harus menggunakan kueri mentah untuk menghindari bigIncrements() mencoba membuat kunci utama lain.

Solusi:

table.bigincrements();
table.biginteger('other').notNullable();
table.dropPrimary();
table.primary(['id', 'other']);

Jika saya memahami penyelidikan sebelumnya tentang topik ini dengan benar, maka knex memaksa kunci primer secara ketat karena beberapa DB (yaitu MySQL) tidak dapat membuat serial tanpa itu menjadi kunci utama? Jika demikian, saya tidak akan terlalu khawatir tentang kompatibilitas mundur ketika datang ke Postgres.

Pengguna MySQL kemudian akan mengharapkannya menjadi yang utama.
Seorang pengguna Postgres tidak akan melakukannya. _ (Yang terbukti di atas) _

Untuk alasan ini saya pikir cukup aman untuk membuat penyesuaian di Postgres ke _not_ force primary key, dan menambahkannya ke changelog. Bukan sebagai patch, tapi untuk versi mayor berikutnya.

Untuk alasan ini saya pikir cukup aman untuk membuat penyesuaian di Postgres untuk tidak memaksakan kunci utama, dan menambahkannya ke log perubahan. Bukan sebagai patch, tapi untuk versi mayor berikutnya.

Saya kenal puluhan orang yang selalu menulis migrasi mereka hanya dengan menulis hanya table.bigincrements('id') tanpa .primary() juga untuk postgresql, karena selalu bekerja seperti itu.

Saya pikir ada opsi tambahan, yang harus digunakan untuk memberi tahu bahwa kunci utama tidak boleh dibuat, tetapi sepertinya tidak ada. Setidaknya saya tidak menemukan apa pun untuk implementasi postgres / mysql tentang melewatkan pembuatan kunci utama.

Ini akan menjadi kompatibilitas mundur besar yang melanggar perubahan pada migrasi yang saya tidak suka melihat ini terjadi. Jika kita ingin terus menambal API migrasi lama ini, pertama-tama kita perlu menambahkan dukungan pembuatan versi untuk itu untuk mencegah semua orang memperbaiki migrasi lama mereka pada setiap versi knex (perubahan dalam kode migrasi tersebut sangat sulit untuk diverifikasi bekerja sama persis dengan tes otomatis sehingga ini adalah bagian yang sangat rentan dalam kode pengguna knex).

Ada solusi?

Ada berita tentang ini?

Utas ini tidak mendapat banyak perhatian selama beberapa waktu. Saya ingin mengulangi apa yang menurut saya merupakan solusi yang ideal dan kompatibel dengan versi sebelumnya (yang dapat menjadi bagian dari rilis minor apa pun): tambahkan opsi baru ke .increments() , mungkin primaryKey: false , yang mana (untuk DBMS jika memungkinkan) menonaktifkan bagian kunci utama dari fungsinya.

Ini sepenuhnya kompatibel ke belakang karena .increments() mempertahankan perilaku defaultnya.

Bisakah kita menggunakan kenaikan seperti ini? perubahan apapun?

Bagaimana kabarnya? ini benar-benar menyebalkan, terutama di MSSQL, batasan PK tidak dinamai secara default tetapi seperti "PK__requests__DD771E3CC0CD0A5E" jadi saya bahkan tidak bisa menjatuhkannya dan membuat PK di tempat lain.
Saya telah membaca untuk menentukan nama untuk kendala tetapi tidak berfungsi untuk increments ()

Masih belum ada apa-apa?

Akan sangat menyukai parameter opsional dalam .increments juga! Kueri mentah jelas bisa berfungsi, tetapi mengganggu bagi mereka yang menjalankan beberapa DB yang berbeda (misalnya mariadb untuk produksi, sqlite untuk pengujian). Ada pembaruan tentang ini? Sepertinya sudah ada PR yang sudah dibuat , tapi agak diam disana?

Saya setuju lagi, saya sudah membutuhkan 3 kali itu dalam satu proyek.

Masalah yang sama di sini, memiliki parameter tambahan untuk menonaktifkan lapisan PK secara wajar.

Mirip dengan # 2896 yang dapat Anda gunakan untuk MySQL:

t.primary(["cmdId", "deviceId"]);
t.specificType("cmdId", "int(10) unsigned AUTO_INCREMENT").notNullable();
t.string("deviceId", 16).notNullable().references("second_table.deviceId");
Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

lanceschi picture lanceschi  ·  3Komentar

aj0strow picture aj0strow  ·  3Komentar

fsebbah picture fsebbah  ·  3Komentar

mishitpatel picture mishitpatel  ·  3Komentar

legomind picture legomind  ·  3Komentar