Tôi gặp một chút rắc rối trong Google App Engine để đảm bảo rằng dữ liệu của tôi là chính xác khi sử dụng mối quan hệ tổ tiên không có tên chính.Làm cách nào để đảm bảo tính toàn vẹn dữ liệu cho các đối tượng trong công cụ ứng dụng của Google mà không sử dụng tên khóa?
Để tôi giải thích thêm một chút: Tôi có một thực thể mẹ loại và tôi muốn tạo một thực thể con mục. Tôi muốn tạo một hàm lấy tên danh mục và tên mục và tạo cả hai thực thể nếu chúng không tồn tại. Ban đầu tôi đã tạo một giao dịch và tạo cả giao dịch trong trường hợp cần thiết bằng cách sử dụng tên khóa và điều này đã hoạt động tốt. Tuy nhiên, tôi nhận ra rằng tôi không muốn sử dụng tên là chìa khóa vì nó có thể cần phải thay đổi, và tôi đã cố gắng trong phạm vi giao dịch của tôi để làm điều này:
def add_item_txn(category_name, item_name):
category_query = db.GqlQuery("SELECT * FROM Category WHERE name=:category_name", category_name=category_name)
category = category_query.get()
if not category:
category = Category(name=category_name, count=0)
item_query = db.GqlQuery("SELECT * FROM Item WHERE name=:name AND ANCESTOR IS :category", name=item_name, category=category)
item_results = item_query.fetch(1)
if len(item_results) == 0:
item = Item(parent=category, name=name)
db.run_in_transaction(add_item_txn, "foo", "bar")
Những gì tôi thấy khi tôi cố gắng chạy này là App Engine từ chối điều này vì nó sẽ không cho phép bạn chạy truy vấn trong một giao dịch: Only ancestor queries are allowed inside transactions
.
Nhìn vào example Google cung cấp cho về cách giải quyết vấn đề này:
def decrement(key, amount=1):
counter = db.get(key)
counter.count -= amount
if counter.count < 0: # don't let the counter go negative
raise db.Rollback()
db.put(counter)
q = db.GqlQuery("SELECT * FROM Counter WHERE name = :1", "foo")
counter = q.get()
db.run_in_transaction(decrement, counter.key(), amount=5)
Tôi đã cố gắng để di chuyển của tôi lấy chủng loại để trước khi giao dịch:
def add_item_txn(category_key, item_name):
category = category_key.get()
item_query = db.GqlQuery("SELECT * FROM Item WHERE name=:name AND ANCESTOR IS :category", name=item_name, category=category)
item_results = item_query.fetch(1)
if len(item_results) == 0:
item = Item(parent=category, name=name)
category_query = db.GqlQuery("SELECT * FROM Category WHERE name=:category_name", category_name="foo")
category = category_query.get()
if not category:
category = Category(name=category_name, count=0)
db.run_in_transaction(add_item_txn, category.key(), "bar")
này dường như làm việc, nhưng tôi tìm thấy khi tôi chạy điều này với một số yêu cầu mà tôi đã tạo các danh mục trùng lặp, điều này có ý nghĩa, vì danh mục được truy vấn bên ngoài giao dịch và nhiều yêu cầu có thể tạo nhiều danh mục.
Có ai có ý tưởng nào về cách tôi có thể tạo các danh mục này đúng cách không? Tôi đã cố gắng để tạo danh mục thành một giao dịch, nhưng đã nhận được lỗi về truy vấn tổ tiên chỉ một lần nữa.
Cảm ơn!
Simon
Bạn đang cố gắng tránh sử dụng tên khóa cho Danh mục? Cách tiêu chuẩn để đảm bảo tính duy nhất là sử dụng db.get_or_insert (parent, key_name). – mahmoud
Vâng, lý do đó tôi tránh điều đó là vì tên danh mục có thể thay đổi và nếu tôi đổi tên nhưng có khóa là tên cũ, tôi sợ mọi thứ sẽ rất khó hiểu ... – Simon