2010-05-03 1 views
29

Есть ли компактный способ с ActiveRecord для запроса того, какой идентификатор он будет использовать следующим, если объект будет сохранен в базе данных? В SQL запрос, как это будет выглядеть примерно так:Ruby on Rails: Как получить ActiveRecord, чтобы показать следующий идентификатор (последний + 1)?

SELECT max(id) + 1 FROM some_table; 
+1

Это зависит от базы данных, которую вы используете, и если записи были удалены .....ПРИМЕР: удалите последние 1000 записей в таблице postgresql и выполните вставку. Идентификатор не является максимальным +1. В парадокс-параме, следующая запись может получить более ранний идентификатор, потому что он повторно использует их. Это действительно зависит от вашей БД. – baash05

+0

Также ... если у вас есть два человека, которые вошли в систему, и оба входят в продукты/purchase_orders/jobs/events. Это вернет одинаковый идентификатор для обоих. – baash05

+2

Простой ответ: вы не делаете этого так, вы создаете модель генератора идентификаторов/поставщиков. – ocodo

ответ

-37

Think это должно работать:

YourModel.last.id + 1 
+3

Что делать, если вы запустили 'YourModel.last.delete', а затем' YourModel.last.id + 1'? не будет ли возвращать номер один меньше следующего идентификатора? – BananaNeil

+2

Не работает, если таблица пуста, а следующий первичный ключ не равен 1. – jspooner

+7

Это не совсем хороший ответ. Он не только не работает в вышеупомянутых случаях, но не работает в очень транзакционной среде с многочисленными вставками. @randombits, может быть, вы хотите изменить принятый ответ на этот вопрос, чтобы не управлять людьми в неправильном направлении? – WattsInABox

29

Принимая fig's answer я мог бы обратить ваше внимание на мелочи. Если вы доберете следующий ID до определенной записи перед сохранением, я думаю, что это не очень хорошая идея.

, потому что, как, например, в системе, основанной на веб-

  1. вы получите последний идентификатор, как 10
  2. установить следующий идентификатор, как 11
  3. перед сохранением записи кто-то другой сохранил запись Теперь последний идентификатор должен быть 12 также ..

Я не уверен, что вы хотите, последний идентификатор, чтобы делать то, что я имею в виду здесь, Но если это так, это просто обратить ваше внимание.

+0

возможно он должен получить его after_save –

1

Я не думаю, что существует общий ответ на этот вопрос, поскольку вы можете не захотеть считать одну базу данных другой. Oracle, например, может назначать идентификатор последовательностью или, что еще хуже, с помощью триггера.

Что касается других баз данных, их можно настроить с помощью несекретного или случайного распределения идентификационных данных.

Могу ли я спросить, что такое прецедент? Зачем вам нужно ожидать следующего идентификатора? Что означает «следующий»? Относительно того, когда? Что относительно условий гонки (многопользовательская среда)?

12

Немного лучше, чем принято отвечать:

YourModel.maximum(:id) + 1 

Тем не менее склонен к гонке-условию и т.д., но, по крайней мере, он будет принимать к сведению пропущенных идентификаторов и немного более эффективный, чем, скажем, приказывая таблицу по идентификатору затем возвращает последнее.

+0

это ненадежность. Если модель с наивысшим id (n) была удалена, то это решение вернет значение n-1 + 1 или просто n. Но следующий идентификатор, который будет назначен, на самом деле равен n + 1. –

+0

Да - как отмечено, это не идеально, только лучше, чем принятый ответ :) Он будет последовательно возвращать идентификатор, который не будет принят. –

+1

Поскольку 'YourModel.maximum (: id)' возвращает 'nil' для пустой таблицы, вам может понравиться:' (YourModel.maximum (: id) || 0) + 1'. Маловероятно, что это проблема в установленной производственной системе, но может быть более надежной в новой или тестовой среде. –

65

Здесь немного изменен Taryn East «s версия:

Model.maximum(:id).next 
+2

IMHO Вы можете указать это как комментарий для пользователя Taryn's – Micha

+1

У меня недостаточно голосов/баллов, чтобы комментировать :( – kimerseen

+0

:-) Хорошо, извините. Возьмите его как рекомендацию на время с достаточным количеством очков. – Micha

1

Там, кажется, нуждается в ответ здесь, удаляющий условия гонки, и решает актуальную проблему предварительного предоставления уникальных идентификаторов.

Для решения проблемы у вас есть вторая модель, которая обслуживает уникальные идентификаторы для основной модели. Таким образом, у вас нет каких-либо условий гонки.

Если вам нужно сделать эти идентификаторы безопасными, вы должны использовать их с SHA256 (или SHA512) и сохранить хеш в качестве проиндексированного столбца в модели идентификатора при их создании.

Затем они могут быть связаны и проверены при использовании на первичной модели. Если вы не используете их, вы все равно связываете их, чтобы обеспечить проверку.

Я отправлю несколько примеров кода чуть позже.

2

Если вы хотите быть уверенным, что никто другой не может принять «новый» индекс, вы должны заблокировать таблицу. Используя что-то вроде:

ActiveRecord::Base.connection.execute("LOCK TABLES table_name WRITE") 

и

ActiveRecord::Base.connection.execute("UNLOCK TABLES") 

Но это специфично для каждой базы данных.

Единственный правильный ответ для последовательного столбца Идентификатор:

YourModel.maximum(:id)+1 

Если упорядочить вашу модель в объеме по умолчанию, последний и первый будет зависеть от этого порядка.

+0

В пустых таблицах 'YourModel.maximum (: id)' даст нуль. Тогда 'nil + 1' выдаст ошибку – user566245

1

Если ни один другой использует таблицу (в противном случае вы не должны использовать блокировку), можно получить значение автоинкрементного из MySQL, команда SQL является

SELECT auto_increment FROM information_schema.tables 
WHERE table_schema = 'db_name' AND table_name = 'table_name'; 

и команда Rails будет

ActiveRecord::Base.connection.execute("SELECT auto_increment 
    FROM information_schema.tables 
    WHERE table_schema = 'db_name' AND table_name = 'table_name';").first[0] 
1

Получить большой идентификатор на столе

YourModel.maximum(:id)

Это запустит следующий SQL

SELECT MAX("your_models"."id") AS max_id FROM "your_models"

Преобразовать результат в целое число, вызвав to_i. Это важно, так как для пустой таблицы приведенная выше максимальная команда вернет nil. К счастью, nil.to_i возвращает 0.

Теперь, чтобы получить следующий доступный идентификатор, просто добавьте 1 + 1`

Конечный результат:

YourModal.maximum(:id).to_i+1 
9

Если база данных Postgres, вы можете получить следующий идентификатор с этим (пример таблицы под названием «пользователи»):

ActiveRecord::Base.connection.execute("select last_value from users_id_seq").first["last_value"] 

в отличие от других ответов, это значение не зависит от удаления повторного шнуры.

Возможно, есть эквивалент mySQL, но у меня нет одной настройки для подтверждения.

2

Это старый вопрос, но ни один из других ответов не будет работать, если вы удалили последнюю запись:

Model.last.id #=> 10 
Model.last.destroy 
Model.last.id #=> 9, so (Model.last.id + 1) would be 10... but... 
Model.create #=> 11, your next id was actually 11 

Я решил проблему, используя следующий подход:

current_value = ActiveRecord::Base.connection.execute("SELECT currval('models_id_seq')").first['currval'].to_i 
Model.last.id #=> 10 
Model.last.destroy 
Model.last.id #=> 9 
current_value + 1 #=> 11 
0

Дон» t получить намерение, но вы можете подумать об использовании GUID