Datastore: Buat entitas induk dan anak dalam transaksi grup entitas?

Setelah membaca tentang konsep/teori Google Datastore, saya mulai menggunakan paket datastore Go

Skenario: Jenis User dan LinkedAccount mengharuskan setiap pengguna memiliki satu atau lebih akun tertaut (yay, login pihak ketiga). Untuk konsistensi yang kuat, LinkedAccounts akan menjadi turunan dari Pengguna terkait. Pembuatan Pengguna baru kemudian melibatkan pembuatan Pengguna dan Akun Tertaut, tidak hanya satu.

Pembuatan pengguna sepertinya merupakan kasus penggunaan yang sempurna untuk transaksi. Jika, katakanlah pembuatan LinkedAccount gagal, maka transaksi akan gagal. Saat ini hal ini tampaknya tidak mungkin dilakukan. Tujuannya adalah untuk membuat induk dan kemudian anak dalam suatu transaksi.

Menurut dokumen

Semua operasi Datastore dalam suatu transaksi harus beroperasi pada entitas dalam grup entitas yang sama jika transaksi tersebut merupakan transaksi grup tunggal

Kami ingin User dan LinkedAccount baru berada di grup yang sama, jadi bagi saya sepertinya Datastore harus mendukung skenario ini. Ketakutan saya adalah bahwa maksud yang dimaksudkan adalah bahwa operasi pada entitas yang ada dalam grup yang sama dapat dilakukan dalam satu transaksi.

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

Dari sumber perpustakaan sudah jelas mengapa ini tidak berhasil. PendingKey bukan kunci dan kunci yang tidak lengkap tidak dapat digunakan sebagai induk.

Apakah ini merupakan batasan yang diperlukan untuk Datastore atau perpustakaan? Bagi mereka yang berpengalaman dengan persyaratan seperti ini, apakah Anda baru saja mengorbankan konsistensi yang kuat dan menjadikan kedua jenis persyaratan tersebut bersifat global?

Untuk kemampuan Google:

  • penyimpanan data: kunci tidak valid
  • datastore: tidak dapat menggunakan pendingKey sebagai tipe *"google.golang.org/cloud/datastore".Key

person dgh    schedule 17.07.2015    source sumber


Jawaban (1)


Satu hal yang perlu diperhatikan adalah transaksi di Cloud Datastore API dapat beroperasi di hingga 25 entitas grup, namun ini tidak menjawab pertanyaan tentang cara membuat dua entitas dalam grup entitas yang sama sebagai bagian dari satu transaksi.

Ada beberapa cara untuk melakukan pendekatan ini (perhatikan bahwa ini berlaku untuk semua penggunaan Cloud Datastore API, bukan hanya perpustakaan gcloud-golang):

  1. Gunakan nama (string) untuk kunci induk alih-alih meminta Datastore secara otomatis menetapkan ID numerik:

    parentKey := datastore.NewKey(ctx, "Parent", "parent-name", 0, nil)
    childKey := datastore.NewIncompleteKey(ctx, "Child", parentKey)
    
  2. Lakukan panggilan eksplisit ke AllocateIds agar Datastore memilih ID numerik untuk kunci induk:

    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
Terima kasih balasannya. Saya kira pertanyaan saya sebenarnya bermuara pada 'dapatkah kunci yang tertunda/tidak lengkap digunakan sebagai semacam janji dalam suatu transaksi' dan sepertinya jawabannya adalah tidak. Saya lebih suka saran Anda menggunakan AllocationIds karena saya ingin Datastore memilih ID numerik, tetapi kelemahannya adalah AllocationIds tidak tersedia dalam transaksi. Saya akan mengeksplorasi pendekatan ini dan kembali - person dgh; 18.07.2015
comment
Ya, itu cara yang bagus untuk meringkasnya, dan Anda benar bahwa saat ini tidak didukung. Sedangkan untuk AllocationIds: bersifat non-transaksional dalam artian alokasi tidak dibatalkan jika transaksi gagal, namun hal tersebut tidak menghentikan Anda untuk memanggilnya saat transaksi aktif. Jika transaksi gagal, Anda hanya mengalokasikan ID yang tidak digunakan -- bukan masalah besar. - person Ed Davisson; 20.07.2015
comment
Akhir pekan ini saya mengambil pendekatan AllocationIDs untuk melakukan transaksi yang memerlukan kunci lengkap dan memutuskan bahwa sangat kecil kemungkinannya saya perlu mendapatkan kembali id ​​yang dialokasikan tetapi tidak digunakan karena ruangnya sangat besar. - person dgh; 21.07.2015