2009-09-30 61 views
0

我有關於SQLAlchemy的問題。我有包含項目的數據庫,每個項目分配了更多記錄(1:n)。記錄部分存儲在數據庫中,但它在文件系統上也有一個分配的文件(1:1)。SQLAlchemy的 - MapperExtension.before_delete不叫

我想要做的是當記錄從數據庫中刪除,刪除指定的文件。所以我寫了下面MapperExtension:

class _StoredRecordEraser(MapperExtension): 
    def before_delete(self, mapper, connection, instance): 
     instance.erase() 

下面的代碼創建了一個實驗裝置(完整的代碼是在這裏:test.py):

session = Session() 

i1 = Item(id='item1') 
r11 = Record(id='record11', attr='1') 
i1.records.append(r11) 
r12 = Record(id='record12', attr='2') 
i1.records.append(r12) 
session.add(i1) 
session.commit() 

最後,我的問題...下面的代碼工作O.K.和old.erase()方法被稱爲:

session = Session() 
i1 = session.query(Item).get('item1') 
old = i1.records[0] 
new = Record(id='record13', attr='3') 
i1.records.remove(old) 
i1.records.append(new) 
session.commit() 

但是,當我換一個新記錄到record11,這已經是在數據庫的id,但它是不一樣的項目(attr=3),old.erase()不調用。有人知道爲什麼嗎?

由於

+0

作品(SQLAlchemy的0.5.6),即old.erase()被調用。但由於記錄實際上已更新,因此不會以未更改的代碼進行調用。 – 2009-09-30 08:02:20

回答

3

的兩個記錄一個刪除+插入件,最終具有單個齊平內的相同的主鍵被轉換成單個更新現在。這是不是最好的行爲 - 它確實應該刪除然後插入,使分配給這些活動的各種事件如預期(不只是映射器擴展方法,但數據庫級別默認太)被觸發。但是flush()過程是硬連線的,首先執行插入/更新,然後刪除。作爲一種解決方法,您可以在刪除/刪除操作後執行flush(),然後在add/insert中執行另一個操作。

至於刷新目前的行爲,我已經考慮嘗試打破這一點,但它變得非常複雜 - 取決於刪除的插入將不得不在刪除後執行,但取決於插入的更新將不得不事先執行。最終,的UnitOfWork模塊被改寫(大發),考慮到所有插入/更新/刪除將被拓撲排序互相依賴的操作的單個流。這將簡化使用正確的順序執行語句的方法,雖然被設計用於同步基於服務器級別的默認行之間的數據將有所有的新系統,它可能是複雜性會被重新引入,如果原來的「更簡單」的方法花費了太多的時間,對ORM級別已知的插入語句進行簡單的排序,不需要相互進行任何排序。拓撲排序的工作原理比現在更粗糙。當我換一個新記錄的ID爲「record11」我