Hat ActiveRecord eine integrierte Upsert-Funktionalität? Ich weiß, ich könnte es selbst schreiben, aber ich will natürlich nicht, wenn so etwas schon existiert.Upsert in Rails ActiveRecord
Antwort
Model.find_or_initialize
wahrscheinlich macht was Sie wollen. Sie können es mit save
oder update_attributes
ketten, wenn das sinnvoll ist.
Weitere Informationen in der Rails Guides.
Es ist Model.find_or_create auch
Dies ist kein Upsert. Es macht eine Auswahl und dann (optional) eine Einfügung. Während Sie in einer Single-Thread-Welt in einer Multi-Thread-Welt den gleichen Effekt erzielen, benötigen Sie einen tatsächlichen Upsert. – tybro0103
ich auf diese Bibliothek gerade lief: https://github.com/seamusabshere/upsert
Ich habe es noch nicht getestet, aber es sieht vielversprechend aus
ich auf einen Blog-Post geschrieben hatte, Wie können wir das erreichen? Schau es Dir an here.
Sie müssen eine aktive Datensatzerweiterung schreiben. Es wird ungefähr so aussehen.
module ActiveRecordExtension
extend ActiveSupport::Concern
def self.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)
Der IMO Upsert-Mechanismus erfordert eine benutzerdefinierte Konfiguration für jedes Modell.
Die beste Lösung wäre also, eine benutzerdefinierte SQL-Abfrage für ein Modell zu implementieren, z.
insert into <table> (<field_1>, ..., <field_n>)
values (<field_1_value>, ..., <field_n_value>)
on duplicate key update
field_x = field_x_value,
...
field_z = field_z_value;
siehe Kommentar zu Pasta's Antwort – tybro0103
Hat jemand gesehen, dass dies einen Upsert generiert? Der Schienenführer zeigt an, dass das neue Objekt noch nicht in der DB gespeichert ist, so dass ich nicht sehen kann, wie dies ein echtes DB-Upsert ist. Das heißt, wird in einer Multithread-Umgebung nicht zuverlässig funktionieren. – stuckj
Diese Lösung weist Nebenläufigkeitsprobleme auf. Es wird fehlschlagen, wenn ein anderer Thread die Tabelle zwischen 'find_or_initialize' und' save' aktualisiert. –