下一个可用的记录ID

mea*_*eah 4 ruby-on-rails ruby-on-rails-3 rails-activerecord

@user = User.new 
Run Code Online (Sandbox Code Playgroud)

@user.id返回nil,但我需要知道它才能保存.可能吗 ?

Dou*_*las 11

是的你可以!

我有同样的问题并调查了文档.解决这个问题的能力实际上与您的数据库类型密切相关.

OraclePostgresql确实有很多有用的功能来轻松解决这个问题.对于MySQL(oracle)或SkySQL(开源),它似乎更复杂(但仍然可能).如果您需要高级数据库工具,我建议您避免使用这些(MySQL/SkySQL)数据库.

首先,您必须尽可能避免在应用程序设计中避免这种情况,因为在保存之前使用ID是危险的.

可能存在以下情况:您没有任何其他选择:例如,当两个表引用自身时,出于安全原因,您不允许在这些表上使用DELETE或UPDATE.

在这种情况下,您可以使用(PostgreSQL,Oracle)数据库nextval函数生成下一个ID号,而无需实际插入新记录.

将它与find_by_sql rails方法结合使用.

例如,要使用postgreSQL和Rails执行此操作,请选择一个rails模型并添加类方法(而不是实例方法!).这可以通过方法名称开头的" self "字来实现. self告诉Ruby这个方法只能由类使用,而不能由实例变量(用'new'创建的对象)使用.

我的Rails模型:

class MyToy < ActiveRecord::Base

...

  def self.my_next_id_sequence
    self.find_by_sql "SELECT nextval('my_toys_id_seq') AS my_next_id"
  end
end
Run Code Online (Sandbox Code Playgroud)

当您使用Rails迁移生成表时,默认情况下,Rails会自动创建一个名为id的列,并将其设置为主键的表.为了确保您没有得到任何" 重复的主键错误 ",Rails会自动在数据库中创建一个序列并将其应用于id列.对于您在表中插入的每个新记录(行),数据库将自行计算新记录的下一个ID.

Rails自动命名此序列,表名附加"_id_seq".为解释PostgreSQL的NEXTVAL函数必须应用于这个序列在这里.

现在关于find_by_sql,如这里所解释的,它将创建一个 包含类的新对象实例的数组.每个对象都将包含SQL语句生成的所有列.这些列将以属性的形式出现在每个新对象实例中.即使您的类模型中不存在这些属性!

正如您明智地意识到的那样,我们的nextval函数只返回一个值.因此,find_by_sql将创建一个包含具有单个属性单个对象实例的数组.为了便于读取此属性的值,我们将使用"my_next_id"命名生成的SQL列,因此我们的属性将具有相同的名称.

就是这样了.我们可以使用我们的新方法:

my_resulting_array = MyToy.my_next_id_sequence
my_toy_object = my_resulting_array[0]
my_next_id_value = my_toy_object.my_next_id
Run Code Online (Sandbox Code Playgroud)

并使用它来解决我们的死锁情况:

my_dog = DogModel.create(:name => 'Dogy', :toy_id => my_next_id_value)

a_dog_toy = MyToy.new(:my_dog_id => my_dog.id)
a_dog_toy.id = my_next_id_value
a_dog_toy.save
Run Code Online (Sandbox Code Playgroud)

请注意,如果您不使用my_next_id_value,则此ID号将永远丢失.(我的意思是,未来任何记录都不会使用它).

数据库不会等你使用它.如果在任何时候,您的应用程序需要在my_table_example中插入新记录(可能与我们正在使用my_next_id_sequence同时),数据库将始终在您生成的新记录之后立即为此新记录分配一个ID号my_next_id_sequence,考虑到你的my_next_id_value是保留的.这可能会导致my_table_example中的记录看起来没有按创建时间排序.


mu *_*ort 10

不,您在保存之前无法获取ID.ID号来自数据库,但在您调用之前,数据库不会分配ID save.所有这一切都假设您当然正在使用ActiveRecord.