Прошлой ночью, немного почесав голову, я решил воспользоваться следующим решением.Я бы предположил, что это по-прежнему создает некоторые нежелательные накладные расходы для многих сценариев, однако я думаю, что накладные расходы могут быть приемлемыми для моих нужд.
Приведенный ниже код является дополнительной модификацией кода в моем вопросе.В частности, я создал еще один класс Model с именем EGEnforcer (что означает Entity Group Enforcer.)
Идея проста.Если транзакция может обновлять несколько записей, только если они связаны с одной группой сущностей, я должен найти способ связать каждую из моих записей, содержащих мои уникальные значения, с одной и той же группой сущностей.
Для этого ясоздайте запись EGEnforcer при первом запуске приложения.Затем, когда возникает необходимость сделать новую запись в моих моделях, я запрашиваю у EGEnforcer запись, связанную с моими парными моделями.После того, как я получаю свою запись EGEnforcer , я делаю ее родителем обеих записей.Виола!Теперь все мои данные связаны с одной и той же группой сущностей.
Поскольку параметр * key_name * уникален только для групп parent-key_name, это должно информировать мои ограничения уникальности, поскольку все мои FirstEntity (ранее ParentEntity ) записи будут иметь одного и того же родителя.Аналогично, мое SecondEntity (ранее ChildEntity ) также должно иметь уникальное значение, сохраняемое как имя_ключа, поскольку родительский элемент также всегда одинаков.
Поскольку оба объекта также имеютодин и тот же родитель, я могу выполнить эти записи в рамках одной транзакции.Если один из них терпит неудачу, все они терпят неудачу.
#My new class containing unique entries for each pair of models associated within one another.
class EGEnforcer(db.Model):
KEY_NAME_EXAMPLE = 'arbitrary unique value'
@staticmethod
setup():
''' This only needs to be called once for the lifetime of the application. setup() inserts a record into EGEnforcer that will be used as a parent for FirstEntity and SecondEntity entries. '''
ege = EGEnforcer.get_or_insert(EGEnforcer.KEY_NAME_EXAMPLE)
return ege
class FirstEntity(db.Model):
str1_key = db.StringProperty()
str2 = db.StringProperty()
@staticmethod
def InsertData(string1, string2, string3):
try:
def txn():
ege = EGEnforcer.get_by_key_name(EGEnforcer.KEY_NAME_EXAMPLE)
prt = FirstEntity(
key_name=string1,
parent=ege) #Our EGEnforcer record.
prt.put()
child = SecondEntity(
key_name=string2,
parent=ege, #Our EGEnforcer record.
parentEnt=prt,
str1=string1,
str2_key=string2,
str3=string3)
child.put()
return child
#This works because our entities are now part of the same entity group
db.run_in_transaction(txn)
except Exception, e:
raise e
class SecondEntity(db.Model):
#foreign and primary key values
str1 = db.StringProperty()
str2_key = db.StringProperty()
#This is no longer a "parent" but a reference
parentEnt = db.ReferenceProperty(reference_class=ParentEntity)
#Other data...
str3 = db.StringProperty()
Одна быстрая заметка - Ник Джонсон определил мою потребность в этом решении:
Это решение может быть достаточным для ваших нужд - дляНапример, если вам нужно обеспечить, чтобы у каждого пользователя был уникальный адрес электронной почты, но это не ваш основной идентификатор пользователя, вы можете сначала вставить запись в таблицу «электронных писем», а затем, если это удастся, вставить свою основную запись.
Это именно то, что мне нужно, но мое решение, очевидно, немного отличается от вашего предложения.Мой метод позволяет транзакции полностью произойти или полностью провалиться.В частности, когда пользователь создает учетную запись, он сначала входит в свою учетную запись Google.Затем они вынуждены перейти на страницу создания учетной записи, если нет записи, связанной с их учетной записью Google в SecondEntity (что на самом деле UserAccount формирует мой фактический сценарий.) Если процесс вставки завершается неудачноони перенаправляются на страницу создания с указанием причины этой ошибки.
Это может быть связано с тем, что их идентификатор не является уникальным или, возможно, является тайм-аутом транзакции.Если при добавлении новой учетной записи пользователя истечет время ожидания, я захочу узнать об этом, но в ближайшем будущем я реализую некоторую форму проверки и баланса.Сейчас я просто хочу начать работу, но это ограничение уникальности является абсолютной необходимостью.
Поскольку мой подход основан исключительно на создании учетной записи, и данные моей учетной записи не изменятся после создания, я считаю, что это должноработать и масштабироваться довольно долго.Я открыт для комментариев, если это неправильно.