我有一个数据流,其中包含类别。我想维护一个类别表,它应该包含我遇到的每个类别一次。如何在ActiveRecord中为PostgreSQL实现'upsert`?
我想实现一个id = Category.upsert(name)
,它应该是原子的(当然),并且 - 如果可能的话 - 不要在DB端使用存储过程。
我有一个数据流,其中包含类别。我想维护一个类别表,它应该包含我遇到的每个类别一次。如何在ActiveRecord中为PostgreSQL实现'upsert`?
我想实现一个id = Category.upsert(name)
,它应该是原子的(当然),并且 - 如果可能的话 - 不要在DB端使用存储过程。
The upsert
gem seems to do just that - 我发现它时,谷歌搜索是否“upsert”是一件事。
如何:
class Category < ActiveRecord::Base
...
class << self
def upsert(name)
transaction { self.find_or_create_by(name: name).id }
end
end
end
不错,但据我了解 - 它有两次往返数据库......你知道一个方法来做一次往返吗? –
你是对的,它的确如此,但据我所知,没有存储过程的人不能做得更好。 – lacrosse
你必须写一个ActiveRecordExtension。检查this了。
该代码将是这个样子
module ActiveRecordExtension
extend ActiveSupport::Concern
def upsert(attributes)
begin
create(attributes)
rescue ActiveRecord::RecordNotUnique, PG::UniqueViolation => e
find_by_primary_key(attributes['primary_key']).
update(attributes)
end
end
end
ActiveRecord::Base.send(:include, ActiveRecordExtension)
这个解决方案几乎不是原子的 - 它甚至不做两次往返 - 它有三个... –
看起来很有趣,但它使用存储过程,而它似乎并没有返回ID /物件(我需要...)。 –