2011-11-29 32 views
15

Ứng dụng của tôi cho phép người dùng tạo và xóa các đối tượng Site. Tôi đã triển khai điều này bằng cách sử dụng session.add()session.delete(). Sau đó tôi có các nút 'Lưu' và 'Đặt lại' gọi session.commit()session.rollback().Xóa một đối tượng khỏi phiên SQLAlchemy trước khi nó được lưu giữ

Nếu tôi thêm Site mới, sau đó lưu/cam kết và sau đó xóa, mọi thứ sẽ ổn. Tuy nhiên, nếu tôi cố xóa một đối tượng khỏi phiên trước khi nó được lưu, tôi sẽ nhận được lỗi 'không được duy trì'.

Code:

self.newSite = Site('foo') 
self.session.add(self.newSite) 
print self.session.new 
self.session.delete(self.newSite) 

Output:

IdentitySet([<Site('foo')>]) 

Traceback (most recent call last): 
    File "C:\Program Files\Eclipse\dropins\plugins\org.python.pydev.debug_2.2.1.2011071313\pysrc\pydevd_comm.py", line 744, in doIt 
    result = pydevd_vars.evaluateExpression(self.thread_id, self.frame_id, self.expression, self.doExec) 
    File "C:\Program Files\Eclipse\dropins\plugins\org.python.pydev.debug_2.2.1.2011071313\pysrc\pydevd_vars.py", line 375, in evaluateExpression 
    result = eval(compiled, updated_globals, frame.f_locals) 
    File "<string>", line 1, in <module> 
    File "C:\Python27\Lib\site-packages\sqlalchemy\orm\session.py", line 1245, in delete 
    mapperutil.state_str(state)) 
InvalidRequestError: Instance '<Site at 0x1ed5fb0>' is not persisted 

tôi hiểu những gì đang xảy ra ở đây, nhưng tôi không chắc chắn những gì tôi nên làm để thay thế.

Có phương pháp nào khác để xóa đối tượng chưa tồn tại khỏi phiên không? Hoặc tôi có nên gọi session.flush() trước khi thử xóa, trong trường hợp đối tượng tôi muốn xóa chưa được xóa chưa?

Nếu đó là sau, cách tự động xóa (đảm bảo rằng các đối tượng đang chờ hiển thị trong kết quả truy vấn), nhưng session.delete() không (đảm bảo rằng các đối tượng đang chờ xử lý có thể bị xóa mà không có lỗi).

Trả lời

13

Bạn có thể Session.expunge(). Tôi nghĩ lý do với delete() là như vậy, nó lo lắng bạn không theo dõi mọi thứ nếu bạn gửi nó đang chờ xử lý. Nhưng tôi có thể thấy mặt khác của câu chuyện về điều đó, tôi sẽ nghĩ về nó. Về cơ bản, nhà nước ngụ ý bởi delete() bao gồm một số giả định về sự kiên trì nhưng chúng có thể không đáng kể như tôi đang nghĩ. Một phương pháp "xóa hoặc xóa" sau đó xuất hiện trong tâm trí, điều đó thật thú vị về cơ bản là "lưu hoặc cập nhật" chúng tôi đã sao chép từ Hibernate, vốn đã trở thành "thêm". "add" có thể thực hiện các chuyển đổi của transient-> pending cũng như tách rời-> persistent - một tiềm năng "remove()" có thực hiện cả hai đang chờ -> thoáng qua và liên tục-> bị xóa không? quá xấu phiên scoped đã có "remove()" ....

Session.query() tự động điền vì nó sắp ra khỏi cơ sở dữ liệu để phát ra một số SQL để nhận một số hàng; vì vậy bất cứ điều gì bạn có tại địa phương cần phải đi ra ngoài đầu tiên. delete() chỉ đánh dấu trạng thái của một đối tượng để không cần phải gọi bất kỳ SQL nào. Nếu chúng tôi muốn delete() để giải quyết vấn đề đang chờ xử lý, chúng tôi sẽ chỉ thay đổi xác nhận đó.

Điều thú vị là, nếu bạn rollback() phiên, bất kỳ phiên bản nào bạn đã add() 'được chỉnh sửa trong phiên đó, có bị xóa hay không, sẽ bị xóa.

+3

Tôi đồng ý với Mike rằng 'xóa' có thể tha thứ hơn. Tuy nhiên, tình hình hiện tại được đơn giản hóa nhiều - có thể có các đối tượng liên quan khác được rõ ràng hoặc ngầm (thông qua quan hệ) được thêm vào cùng một phiên và không được cam kết. Vì vậy, IMO, cách sạch nhất là thực hiện một 'rollback()' trên phiên làm việc. – van

+0

Cảm ơn, điều đó có ý nghĩa bây giờ. Vì vậy, khi nút xóa được nhấp, logic nên là gì? Một cái gì đó như 'try: session.delete (foo); ngoại trừ InvalidRequestError: session.expunge (foo) '? Hoặc, theo [câu trả lời này] (http://stackoverflow.com/a/3897845/665488), có thể: 'if has_identity (foo): session.delete (foo); else: session.expunge (foo) '? –

+5

Tôi có thể nói "nếu đối tượng trong phiên.new: expunge else: delete" – zzzeek

Các vấn đề liên quan