2013-01-23 49 views
8

Cập nhật:SQLAlchemy hai chiều Mối quan hệ gắn Proxy

Đối với bất cứ ai có vấn đề này, với very latest SQLAlchemy hành vi này đã được sửa.

gốc vấn đề:

Tôi gặp một vấn đề với nhận proxy hiệp hội để cập nhật một cách chính xác.

Sử dụng các mô hình ví dụ ở đây: http://docs.sqlalchemy.org/en/rel_0_7/orm/extensions/associationproxy.html#simplifying-association-objects

Nhưng thay đổi UserKeyword với dòng này:

keyword = relationship("Keyword", backref=backref("user_keywords", cascade="all, delete-orphan")) 

và thêm này để theo từ khóa:

users = association_proxy('user_keywords', 'user') 

Vì vậy, một trường hợp từ khóa có một danh sách người dùng.

Các công trình sau đây như mong đợi:

>>> rory = User("rory") 
>>> session.add(rory) 
>>> chicken = Keyword('chicken') 
>>> session.add(chicken) 
>>> rory.keywords.append(chicken) 
>>> chicken.users 
[<__main__.User object at 0x1f1c0d0>] 
>>> chicken.user_keywords 
[<__main__.UserKeyword object at 0x1f1c450>] 

Nhưng ñuoåi làm những điều kỳ lạ. Xóa khỏi danh sách proxy liên kết như vậy:

>>> rory.keywords.remove(chicken) 

Gây ra lỗi toàn vẹn khi SA cố gắng đặt một trong các cột khóa ngoài thành rỗng.

Việc làm này:

>>> rory.user_keywords.remove(rory.user_keywords[0]) 

Kết quả trong này:

>>> chicken.users 
[None] 

tôi đã bỏ lỡ một cái gì đó rõ ràng có phải không?

Trả lời

7

UserKeyword yêu cầu phải liên kết với cả KeywordUser cùng một lúc để duy trì. Khi bạn liên kết nó với một số UserKeyword, nhưng sau đó xóa nó khỏi bộ sưu tập User.user_keywords, nó vẫn được liên kết với Keyword.

>>> rory.keywords.remove(chicken) 

# empty as we expect 
>>> rory.user_keywords 
[] 

# but the other side, still populated. UserKeyword 
# has no User, but still has Keyword 
>>> chicken.user_keywords 
[<__main__.UserKeyword object at 0x101748d10>] 

# but the User on that UserKeyword is None 
>>> chicken.user_keywords[0].user is None 
True 

# hence accessing the "association" gives us None 
# as well 
>>> chicken.users 
[None] 

Vì vậy, nếu chúng ta tuôn() này ngay bây giờ, bạn đã có một UserKeyword đối tượng sẵn sàng để đi nhưng nó không có User vào nó, vì vậy bạn nhận được rằng lỗi NULL. Tại thời điểm INSERT, đối tượng không được coi là "trẻ mồ côi" trừ khi nó không được liên kết với bất kỳ bộ sưu tập nào Keyword.user_keywordshoặcUser.user_keywords. Chỉ khi bạn nói, del chicken.user_keywords[0] hoặc tương đương, bạn sẽ thấy rằng không có INSERT nào được tạo và đối tượng UserKeyword bị lãng quên.

Nếu bạn đã xóa đối tượng vào cơ sở dữ liệu trước khi xóa nó khỏi "rory", thì mọi thứ sẽ thay đổi. UserKeyword hiện đang tồn tại và khi bạn xóa "gà" khỏi "rory".Từ khóa", một "delete-mồ côi" cháy sự kiện tắt mà không xóa UserKeyword, mặc dù nó vẫn còn được kết hợp với Keyword đối tượng:

rory.keywords.append(chicken) 

session.flush() 

rory.keywords.remove(chicken) 

session.flush() 

bạn thấy SQL:

INSERT INTO "user" (name) VALUES (%(name)s) RETURNING "user".id 
{'name': 'rory'} 

INSERT INTO keyword (keyword) VALUES (%(keyword)s) RETURNING keyword.id 
{'keyword': 'chicken'} 

INSERT INTO user_keyword (user_id, keyword_id, special_key) VALUES (%(user_id)s, %(keyword_id)s, %(special_key)s) 
{'keyword_id': 1, 'special_key': None, 'user_id': 1} 

DELETE FROM user_keyword WHERE user_keyword.user_id = %(user_id)s AND user_keyword.keyword_id = %(keyword_id)s 
{'keyword_id': 1, 'user_id': 1} 

Bây giờ một người hợp lý sẽ hỏi, "không phải là không nhất quán?" Và tại thời điểm này tôi muốn nói, "tuyệt đối". Tôi cần phải nhìn vào các trường hợp thử nghiệm để xem lý do là gì cho sự khác biệt này trong hành vi, tôi ' đã được xác định trong mã tại sao nó xảy ra theo cách này và tôi khá chắc chắn sự khác biệt này trong cách một "đứa trẻ mồ côi" được xem xét ered cho "đang chờ xử lý" so với "kiên trì" đối tượng là cố ý, nhưng trong hoán vị cụ thể này rõ ràng là tạo ra một kết quả lạ. Tôi có thể thực hiện một thay đổi trong 0.8 cho điều này nếu tôi có thể tìm thấy một trong đó là khả thi.

chỉnh sửa: http://www.sqlalchemy.org/trac/ticket/2655 tóm tắt vấn đề mà tôi sẽ phải suy nghĩ. Có một thử nghiệm cho hành vi này đặc biệt, cần phải theo dõi trở lại nguồn gốc của nó.

+0

Cảm ơn heaps zzzeek. –

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