Rails ActiveRecord:获取原始插入的id

7
sql = DmozCategory.send(:sanitize_sql_array, ["INSERT INTO dmoz_categories (id, dmoz_category_title, dmoz_category_name, dmoz_category_description, created_at, updated_at, dmoz_category_lastupdate) VALUES (?, ?, ?, ?, NOW(), NOW(), ?)", result['catid'], result['title'], result['name'], result['description'], result['lastupdate']])

res = DmozCategory.connection.execute(sql)
$stderr.puts res.inspect

res 总是 nil,即使我可以看到 DmozCategory 插入到数据库中。如何获得插入后的 id

我知道我可以使用另一个 SQL 查询 SELECT LAST_INSERT_ID() 来获取 ID,但我想知道是否有一种通过 Rails 获取 ID 的方法。

背景:使用 Rails 2.3.14

更新:嗯,我想问题出在我正在使用的一个名为 Octopus 的插件上。抱歉忽略了你们的一些答案...看起来我需要找到如何使用此插件获取插入的最后一个 id。我的完整代码:

desc "load all categories from dmoz" # With this one we're loading all the 'structure' table in, not the parent-child relationships.
  task :load_categories_from_dmoz, [ :offset, :limit ] => :environment do |t, args|
    offset = !args[:offset].blank? ? args[:offset].to_i : 0 # Take offset from args.  Default of 0
    limit = !args[:limit].blank? ? args[:limit].to_i : 1 # Take limit from args.  Default of 1
    ActiveRecord::Base.octopus_establish_connection(:adapter=> "mysql", :host=> "localhost", :database => "dmoz", :username => "dmoz", :password => "dmoz")

    results = ActiveRecord::Base.connection.select_all("SELECT * FROM structure LIMIT #{ offset }, #{ limit }") # Fetches it directly from the dmoz database.
    count = offset
    conn = ActiveRecord::Base.octopus_establish_connection(:adapter=> "mysql", :host=> "localhost", :database => "talon_development", :username => "rails_shadow", :password => "husky")
    results.each do |result|
      if count % 1000 == 0
        puts count
      end
      count +=1

      begin
        sql = DmozCategory.send(:sanitize_sql_array, ["INSERT INTO dmoz_categories (id, dmoz_category_title, dmoz_category_name, dmoz_category_description, created_at, updated_at, dmoz_category_lastupdate) VALUES (?, ?, ?, ?, NOW(), NOW(), ?)", result['catid'], result['title'], result['name'], result['description'], result['lastupdate']]) #We leave parent_id NULL for the next task to handle relationships

        DmozCategory.connection.execute(sql) #doesn't get the ID..

      end
    end
  end

尝试使用 exec_querylast_inserted_id(res) - Yuri Barbashov
@YuriBarbashov 我认为在Rails 2.3.14中没有这个功能? - Ben G
你不是自己插入了id吗?INSERT INTO dmoz_categories (id, ...) VALUES (?, ...), result['catid'], ... - Wawa Loo
是的,但我想稍后检查一下它是否有效。不确定它是否已经生效。 - Ben G
6个回答

14

通常情况下应该使用connection.insert而不是connection.execute

这样会返回最后插入行的生成id,如何实现取决于数据库。在MySQL中,最后一个插入id是连接的属性。在Postgres中,查询后面会附加“returning”子句(在旧版本的Postgres中,回退会询问序列它的最后一个id)。

使用insert而不是execute还会清除Rails查询缓存。

至少在MySQL中,即使您自己设置了id,这也将起作用。


我该如何获取id?DmozCategory.connection.idDmozCategory.connection.last_id似乎没有我插入的id。 - Ben G
连接.insert "INSERT ..." 应该返回id(假设您的id是一个常规的自动增量列) - Frederick Cheung
哦,所以我不需要先使用.send吗?它可以一次性完成发送和执行的操作? - Ben G
针对.send的问题,请仅获取SQL。DmozCategory.connection.insert(sql)返回0,且DmozCategory.connection.id返回2223123080,尽管我可以看到它已插入具有id为2的表中。 - Ben G
如果您正在使用PostgreSQL上的Foreign Data Wrapper,那么调用#insert将不会自动使用RETURNING。但是,您可以将其添加到在远程服务器上运行的INSERT命令中,并返回远程ID。请参阅文档以获取有关INSERT ... RETURNING示例的详细信息。 - jwadsack

1

我认为insert_sql方法应该能帮到你。

DmozCategory.connection.insert_sql(sql) # => id

0

既然你已经知道了id,那么你就可以这样做吗?

dmoz_category = DmozCategory.find(result['id'])
$stderr.puts dmoz_category.inspect

看起来这似乎是唯一的方法。不知道为什么,但其他所有方法都返回0或巨大/错误的数字。 - Ben G

0

试试这个,这就是AR在2.3版本中定义插入前的id的方式

id = DmozCategory.connection.next_sequence_value(DmozCategory.sequence_name)


“undefined method next_sequence_value' for #<ActiveRecord::ConnectionAdapters::MysqlAdapter:0x10d1de1e8>” 的含义是“未定义方法 next_sequence_value' 于 #ActiveRecord::ConnectionAdapters::MysqlAdapter:0x10d1de1e8”。 - Ben G

0
如果这是mysql2 gem,并且 DmozCategory.connection 是客户端的一个实例,那么DmozCategory.connection.last_id 将会起作用。

我正在使用 mysql,所以出现了 undefined method last_id' for #ActiveRecord::ConnectionAdapters::MysqlAdapter:0x106d82d48` 的错误。 - Ben G

-1
假设您正在使用MYSQL并且表自动增量,您可以使用以下代码:
SELECT LAST_INSERT_ID()

要做到它所说的,需要获取插入到表中的最后一个ID。这将向您的代码添加另一个查询,但似乎仍然使用原始SQL。


如果可能的话,我更喜欢使用 Rails 的方式处理这个问题。那是唯一的方法吗? - Ben G
你可以像这样做:DmozCategory.find(:last).id - BK22
我不确定那是否可能,抱歉。 - BK22

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接