Хранилище данных: создать родительскую и дочернюю сущности в транзакции группы сущностей?

Прочитав о концепциях / теории Google Datastore, я начал использовать пакет хранилища данных Go

Сценарий: Виды User и LinkedAccount требуют, чтобы у каждого пользователя была одна или несколько связанных учетных записей (yay сторонний вход). Для большей согласованности LinkedAccounts будет дочерним элементом связанного пользователя. Затем создание нового пользователя включает в себя создание как пользователя, так и LinkedAccount, а не только одного.

Создание пользователей кажется идеальным вариантом использования для транзакций. Если, скажем, создание LinkedAccount не удалось, транзакция откатится и завершится ошибкой. В настоящее время это не представляется возможным. Цель состоит в том, чтобы создать в транзакции родителя, а затем потомка.

Согласно документам

Все операции с хранилищем данных в транзакции должны работать с объектами в одной группе объектов, если транзакция является одной групповой транзакцией.

Мы хотим, чтобы новые User и LinkedAccount находились в одной группе, поэтому мне кажется, что хранилище данных должно поддерживать этот сценарий. Я опасаюсь, что предполагаемое значение состоит в том, что операции с существующими объектами в одной группе могут выполняться за одну транзакцию.

tx, err := datastore.NewTransaction(ctx)
if err != nil {
    return err
}
incompleteUserKey := datastore.NewIncompleteKey(ctx, "User", nil)
pendingKey, err := tx.Put(incompleteUserKey, user)
if err != nil {
    return err
}
incompleteLinkedAccountKey := datastore.NewIncompleteKey(ctx, "GithubAccount", incompleteUserKey)
// also tried PendingKey as parent, but its a separate struct type
_, err = tx.Put(incompleteLinkedAccountKey, linkedAccount)
if err != nil {
    return err
}
// attempt to commit
if _, err := tx.Commit(); err != nil {
    return err
}
return nil

Из источника библиотеки становится ясно, почему это не работает. PendingKey не являются ключами, а неполные ключи нельзя использовать в качестве родительских.

Это необходимое ограничение хранилища данных или библиотеки? Для тех, у кого есть опыт работы с требованиями такого типа, неужели вы просто пожертвовали строгой согласованностью и сделали оба вида глобальными?

Для Google-способности:

  • хранилище данных: неверный ключ
  • хранилище данных: нельзя использовать pendingKey как тип * "google.golang.org/cloud/datastore" .Key

person dgh    schedule 17.07.2015    source источник


Ответы (1)


Следует отметить, что транзакции в Cloud Datastore API могут работать до 25 объектов. groups, но это не отвечает на вопрос о том, как создать две сущности в одной группе сущностей в рамках одной транзакции.

Есть несколько способов подойти к этому (обратите внимание, что это относится к любому использованию Cloud Datastore API, а не только к библиотеке gcloud-golang):

  1. Используйте (строковое) имя для родительского ключа вместо автоматического присвоения Datastore числового идентификатора:

    parentKey := datastore.NewKey(ctx, "Parent", "parent-name", 0, nil)
    childKey := datastore.NewIncompleteKey(ctx, "Child", parentKey)
    
  2. Сделайте явный вызов AllocateIds, чтобы хранилище данных выбрало числовой идентификатор для родительского ключа:

    incompleteKeys := [1]*datastore.Key{datastore.NewIncompleteKey(ctx, "Parent", nil)}
    completeKeys, err := datastore.AllocateIDs(ctx, incompleteKeys)
    if err != nil {
      // ...
    }
    parentKey := completeKeys[0]
    childKey := datastore.NewIncompleteKey(ctx, "Child", parentKey)
    
person Ed Davisson    schedule 17.07.2015
comment
Спасибо за ответ. Я полагаю, мой вопрос действительно сводится к тому, «могут ли ожидающие / неполные ключи использоваться как своего рода обещание в транзакции», и, похоже, ответ отрицательный. Я предпочитаю ваше предложение с использованием AllocateIds bc. Я бы хотел, чтобы Datastore выбрал числовой идентификатор, но недостатком является то, что AllocateIds недоступен в транзакциях. Я изучу эти подходы и вернусь - person dgh; 18.07.2015
comment
Да, это хороший способ резюмировать это, и вы правы, что в настоящее время он не поддерживается. Что касается AllocateIds: он не является транзакционным в том смысле, что выделение не будет отменено в случае сбоя транзакции, но это не мешает вам вызывать его, пока транзакция активна. Если транзакция не удалась, вы просто назначаете идентификатор, который не используется - ничего страшного. - person Ed Davisson; 20.07.2015
comment
В эти выходные я применил подход AllocateIDs для выполнения транзакций, требующих завершения ключа, и решил, что вряд ли мне когда-либо понадобится возвращать выделенные, но неиспользованные идентификаторы, потому что пространство слишком велико. - person dgh; 21.07.2015