2016-06-23 1 views
0

Dieser Code ist ungewöhnlich.
Ich programmiere eine lange laufende Transaktionen (mit Web-API).
Also brauche ich knifflige Programm.
Ich möchte das Rollback-Objekt erneut speichern (piyo2).Warum DB nicht ändern, wie das Rollback-Objekt erneut gespeichert wird

piyo2 = nil 
ActiveRecord::Base.transaction do 
    piyo1 = Piyo.find_by(id: 1) 
    piyo1.name = 'hoge' 
    piyo1.save! 
    piyo2 = Piyo.find_by(id: 2) 
    piyo2.name = 'foo' 
    piyo2.save! 
    raise ActiveRecord::Rollback 
end 
piyo2.save! # log show BEGIN COMMIT. But Not show execute SQL. 
piyo2.name # keep foo. But DB no change. 

Meine Lösung.

piyo2 = nil 
ActiveRecord::Base.transaction do 
    piyo1 = Piyo.find_by(id: 1) 
    piyo1.name = 'hoge' 
    piyo1.save! 
    piyo2 = Piyo.find_by(id: 2) 
    piyo2.name = 'foo' 
    piyo2.save! 
    raise ActiveRecord::Rollback 
end 
piyo2_retry = Piyo.find_by(id: piyo2.id) # one more find_by 
piyo2_retry.update!(name: piyo2.name) 

Dies ist die beste Lösung?
Warum piyo2.save! # log show BEGIN COMMIT. But No execute SQL. dieser Code nicht Wok?

Antwort

0

Sie tun im Grunde das Richtige, obwohl Ihr Beispiel mich mit einiger Verwirrung verlässt.

Hier ist die warum von dem, was Sie sehen.

Sie müssen den Status der Instanz aktualisieren, die Sie in der Hand haben.

Auch wenn Sie die Transaktion zurückgerollt haben, denkt die Instanz in Ihrer Hand es wurde beibehalten und hat den neuen Namen.

puts piyo2.name  # foo 
puts piyo2.persisted? # true 
puts piyo2.changed? # falses 

Rails ist intelligent genug, um nicht tatsächlich SQL ausgeführt werden, wenn das Objekt zur Zeit beibehalten wird und keine Änderungen hat: Sie können durch Aufruf sehen belegt dies. Sie können dies selbst beweisen, indem Sie ein beliebiges Objekt laden und sofort versuchen, es zu speichern. Sie werden BEGIN/COMMIT ohne weitere SQL im Log/Output sehen.

Effektiv ist Ihr Objekt nicht mehr synchron mit der Datenbank. Um den Zustand Ihrer Instanz zurück synchron mit dem db zu erhalten müssen Sie es neu zu laden:

piyo2.reload 

Dies ist, was Sie effektiv tun. Piyo.find piyo2.id generiert das gleiche genaue SQL wie neu laden. Reload ist nur semantisch klarer.

+0

'piyo2.reload' zurück zum Original. Benötigen Sie eine Kopie oder einen Klon 'piyo2'? lile 'tmp_piyo = piyo2.clone' –

+0

Klon ist eine gültige Methode. es wird den Zustand dessen widerspiegeln, was Sie in der Hand haben. dann musst du es natürlich speichern. Aber das schafft ein brandneues Piyo, nicht dauerhafte Änderungen an dem, was Sie in der Hand haben. – jaydel

Verwandte Themen