Knex: لا يمكن إنشاء PKs متعددة (تزايدات mixin مع .primary)

تم إنشاؤها على ١٨ يوليو ٢٠١٤  ·  31تعليقات  ·  مصدر: knex/knex

أرغب في إنشاء جدول يستند إلى ما يلي تفريغ MySQL:

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 الخاص بي:

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

ومع ذلك ، هناك مشكلة في المفاتيح الأساسية. أتلقى الخطأ التالي:

Error: Multiple primary key defined

أفترض أن طريقة increments تخلق بالفعل PK وأن الطريقة primary تخلق طريقة أخرى تسبب خطأ.

هل من الممكن تحقيق هذا الشكل من الجدول؟

bug

التعليق الأكثر فائدة

أو يمكنك إنشاء عمود de autoincrement مع

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

(فقط لـ Postgresql)

ولكن أعتقد أنه من الأفضل بكثير أن يقوم table.increments() بإنشاء PK فقط إذا قمت بتحديد ذلك يدويًا باستخدام table.increments().primary()

ال 31 كومينتر

لا ، ولكن ربما ينبغي أن يكون. سأبحث في شيء من أجل هذا.

وفقًا لـ 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';

لذلك ، ينشئ .increments() PK. أليس هذا سلوكًا قويًا جدًا؟ أعتقد أنه سيكون من الأفضل إنشاء عمود AUTO_INCREMENT بدون PK ، لذلك:

int unsigned not null auto_increment

ولإنشاء PK ، علينا استدعاء .primary() :

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

سيسمح بإنشاء العديد من PKs بعمود AUTO_INCREMENT .

كعمل بديل أستخدمه الآن:

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

وفي then callback:

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

لدي مشكلة مماثلة - أريد استخدام .increments() بدون أن يكون مفتاحًا أساسيًا. في حالتي هو لأسباب تتعلق بالأداء. أرغب في إنشاء الجدول بدون فهارس (مما يعني عدم وجود مفتاح أساسي) ، وإدراج العديد من الصفوف فيه ، ثم إضافة فهرس على عمود التزايد التلقائي. هذا أكثر كفاءة ، وفي الواقع موصى به من قبل وثائق Postgres (انظر http://www.postgresql.org/docs/9.4/static/populate.html#POPULATE-RM-INDEXES) ، ولكن يبدو حاليًا أنه من المستحيل القيام به كنكس.

يبدو أنني واجهت مشكلة مماثلة. لا يمكنني إنشاء جدول يحتوي على:

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

نفس المشكلة هنا تحاول .increments () تحديد مفتاح أساسي ، حتى لو قمت بتحديد مفتاح يدويًا

يمكنك استخدام استعلام خام لإضافة أعمدة زيادات بدون مفتاحها الأساسي:

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');
    }),
  ]);
};

أو يمكنك إنشاء عمود de autoincrement مع

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

(فقط لـ Postgresql)

ولكن أعتقد أنه من الأفضل بكثير أن يقوم table.increments() بإنشاء PK فقط إذا قمت بتحديد ذلك يدويًا باستخدام table.increments().primary()

لماذا لا ترحل
increments: 'serial'
بدلا من
increments: 'serial primary key'

ما هي المشكلة في ذلك؟

ما زلت أحصل على نفس الخطأ.
IMHO .increments يجب ألا ينشئ PK.

أي أخبار بشأن هذه المسألة؟

متفق عليه - في حين أنه من الممكن بالتأكيد حل هذه المشكلة بطرق مختلفة ، فمن الغريب أن واجهة برمجة التطبيقات لا تتمتع بدعم من الدرجة الأولى لإنشاء عمود زيادة تلقائية دون جعله مفتاحًا أساسيًا.

مع ذلك ، أتخيل أن هذا لم يتم إصلاحه بعد على الرغم من أن تصحيح هذا بالطريقة الأكثر منطقية سيكون بمثابة تغيير فاصل ، وبالتالي يجب أن يكون جزءًا من عثرة إصدار رئيسي.

تضمين التغريدة
الشيء هو أننا إذا استخدمنا .primary() على أعمدة عند إنشاء جدول ، فستكون النتيجة استعلامًا منفصلاً لإنشاء الجدول واستعلام alter table لتعريف المفاتيح الأساسية.
أعتقد أنه في MySQL (أو ربما نظم إدارة قواعد البيانات الأخرى أيضًا) ، لا يمكنك الحصول على حقل auto_incremement بدون أن تكون PK.
لذلك ، يقوم knex بإنشاء الجدول بالمفتاح الأساسي ، ومن ثم لا يمكنه فقط alter تحديد مفتاحين أساسيين لأن الجدول يحتوي بالفعل على مفتاح واحد.
إذا تمكنا من إصلاح هذا ، فربما لا يزال .increments ينشئ PK ولكن يسمح للأعمدة الأخرى بأن تكون PK أيضًا في استعلام واحد create table ، لذلك ربما لن نحتاج إلى عثرة إصدار رئيسي.

أو يمكننا إضافة نوع عمود آخر لذلك وترك .increments كما هو لعدم كسر التوافق مع الإصدارات السابقة.

@ amir-s: حسنًا ، هذا يفسر سبب تصرف Knex كما هو - يبدو أنه يحاول أن يكون لديه سلوك مكافئ عبر أنظمة DBMS المختلفة المدعومة. أنا لا أحب ذلك بشكل خاص ، لكن على الأقل لا يبدو غريباً الآن.

تكمن مشكلة اقتراحك في أنه بحكم التعريف لا يمكن أن يكون لديك عدة مفاتيح أساسية على الجدول. (يمكن أن يكون لديك PK مركب واحد على عدة أعمدة ، لكن هذا يختلف تمامًا عن وجود 2 PK من عمود واحد.)

لذلك إذا أنشأ .increments PK ، فمن المستحيل السماح أيضًا بوضع علامة PK على الأعمدة الأخرى. سيكون من الممكن إنشاء خيار يمكن تمريره إلى .increments لتعطيل سلوك المفتاح الأساسي في Postgres وأي نظام DBMS آخر يدعم مثل هذا السلوك. ربما يكون هذا هو الحل الأفضل ، لأنه لا يكسر التوافق مع الإصدارات السابقة ولا يكسر أيضًا التوافق مع DBMS. ما زلت لا أحب ذلك بالإضافة إلى تغيير السلوك الافتراضي على Postgres بحيث لا يجعله .increments أيضًا PK ، ولكنه سيكون أكثر قبولًا للعلاقات العامة.

إذا أراد أي شخص تقديم علاقات عامة على هذا المنوال ، فأنا أجادل لصالحه. :-)

zacronos آسف ، من خلال "عدة PKs" كنت أعني "

بالاتفاق مع جميع التعليقات أعلاه. كان هذا السلوك غير متوقع عند محاولة إنشاء مفتاح أساسي مركّب بالإضافة إلى عمود زيادة تلقائية بدون مفتاح. سيكون من الرائع رؤية هذا التنفيذ.

أنا أواجه هذه المشكلة أيضًا ، ولكن في حالة استخدام Postgres واستخدام الحقول التسلسلية كمفاتيح خارجية - فإن تنفيذ knex للحقل التسلسلي Postgres هو increments() وهذا يجعلها مفاتيح أساسية بشكل افتراضي. أريد أن أكون قادرًا على إنشاء sqlite3 بالإضافة إلى postgres ، لذا فإن استخدام استعلام knex الخام سيقصرني على أحدهما أو. أي اقتراحات حل بديل؟

لم يحظ هذا الموضوع باهتمام كبير منذ فترة. أود أن أكرر ما أعتقد أنه حل مثالي متوافق مع الإصدارات السابقة (والذي يمكن أن يكون جزءًا من أي إصدار ثانوي): أضف خيارًا جديدًا إلى .increments() ، ربما primaryKey: false ، والذي (لنظام إدارة قواعد البيانات حيث يكون ذلك ممكنًا) يعطل جزء المفتاح الأساسي من وظائفه.

هذا متوافق تمامًا مع الإصدارات السابقة نظرًا لأن .increments() يحتفظ بسلوكه الافتراضي.

zacronos ألقوا نظرة سريعة على الكود. تبدو تافهة. سوف نجمع العلاقات العامة
https://github.com/DeedMob/knex/tree/master/src

نفس المشكلة هنا. يجب عليك استخدام الاستعلام الأولي لتجنب bigIncrements() لمحاولة إنشاء مفتاح أساسي آخر.

الحل:

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

إذا فهمت التحقيق السابق حول هذا الموضوع بشكل صحيح ، فحينئذٍ يفرض knex مفتاحًا أساسيًا بشكل صارم لأن بعض قواعد البيانات (أي MySQL) لا يمكنها إنشاء مسلسلات بدون أن تكون مفتاحًا أساسيًا؟ إذا كان هذا هو الحال ، فلن أقلق كثيرًا بشأن التوافق مع الإصدارات السابقة عندما يتعلق الأمر بـ Postgres.

يتوقع مستخدم MySQL بعد ذلك أن يكون ملفًا أساسيًا.
مستخدم Postgres لا. _ (الذي هو واضح أعلاه) _

لهذا السبب أعتقد أنه من الآمن جدًا إجراء تعديل في Postgres على _not_ فرض المفتاح الأساسي وإضافته إلى سجل التغيير. ليس كتصحيح ، ولكن للإصدار الرئيسي التالي.

لهذا السبب أعتقد أنه من الآمن جدًا إجراء تعديل في Postgres لعدم فرض المفتاح الأساسي وإضافته إلى سجل التغيير. ليس كتصحيح ، ولكن للإصدار الرئيسي التالي.

أعرف عشرات الأشخاص الذين كتبوا دائمًا هجراتهم فقط عن طريق كتابة table.bigincrements('id') بدون .primary() أيضًا لـ postgresql ، لأنه كان يعمل دائمًا على هذا النحو.

على الرغم من وجود خيار إضافي ، والذي يجب استخدامه لإخبار أنه لا يجب إنشاء المفتاح الأساسي ، ولكن يبدو أنه غير موجود. على الأقل لم أجد أي شيء لتطبيقات postgres / mysql حول تخطي إنشاء المفتاح الأساسي.

سيكون هذا تغييرًا كبيرًا في التوافق مع الإصدارات السابقة على عمليات الترحيل التي أكرهها لرؤية هذا يحدث. إذا أردنا الاستمرار في تصحيح واجهة برمجة تطبيقات الترحيل القديمة هذه ، فسنحتاج أولاً إلى إضافة دعم الإصدار لها لمنع جميع الأشخاص من إصلاح عمليات الترحيل القديمة في كل إصدار من إصدارات knex (من الصعب حقًا التحقق من هذه التغييرات في رمز الترحيل من العمل بنفس الشيء تمامًا مع اختبارات تلقائية لذلك فهو جزء ضعيف جدًا في كود مستخدم knex).

اي حل؟

أي أخبار عن هذا؟

لم يحظ هذا الموضوع باهتمام كبير منذ فترة. أود أن أكرر ما أعتقد أنه حل مثالي متوافق مع الإصدارات السابقة (والذي يمكن أن يكون جزءًا من أي إصدار ثانوي): أضف خيارًا جديدًا إلى .increments() ، ربما primaryKey: false ، والذي (لنظام إدارة قواعد البيانات حيث يكون ذلك ممكنًا) يعطل جزء المفتاح الأساسي من وظائفه.

هذا متوافق تمامًا مع الإصدارات السابقة نظرًا لأن .increments() يحتفظ بسلوكه الافتراضي.

هل يمكننا استخدام زيادات مثل هذا؟ أي تحديث؟

كيف الحال؟ إنه أمر مؤلم حقًا ، خاصة في MSSQL ، لا يتم تسمية قيود PK افتراضيًا ولكن مثل "PK__requests__DD771E3CC0CD0A5E" لذلك لا يمكنني حتى إسقاطها وإنشاء PK في مكان آخر.
لقد حاولت تحديد اسم للقيد ولكنه لا يعمل مع الزيادات ()

لا يزال هناك شيء على ذلك؟

هل ترغب في استخدام المعلمة الاختيارية في .increments أيضًا! من الواضح أن الاستعلامات الأولية يمكن أن تعمل ، ولكنها مزعجة لأولئك الذين يديرون قواعد بيانات متعددة مختلفة (مثل mariadb للإنتاج ، و sqlite للاختبار). أي تحديثات على هذا؟ يبدو أن هناك علاقات عامة تم إجراؤها بالفعل ، لكنها صمتت نوعًا ما هناك؟

أؤيد ذلك مرة أخرى ، لقد احتجت بالفعل إلى هذه المرة 3 في مشروع واحد.

نفس المشكلة هنا ، وجود معلمة إضافية لتعطيل طبقات PK معقول.

على غرار # 2896 يمكنك استخدامه مع MySQL:

t.primary(["cmdId", "deviceId"]);
t.specificType("cmdId", "int(10) unsigned AUTO_INCREMENT").notNullable();
t.string("deviceId", 16).notNullable().references("second_table.deviceId");
هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات

القضايا ذات الصلة

hyperh picture hyperh  ·  3تعليقات

zettam picture zettam  ·  3تعليقات

koskimas picture koskimas  ·  3تعليقات

saurabhghewari picture saurabhghewari  ·  3تعليقات

aj0strow picture aj0strow  ·  3تعليقات