Datastore: สร้างเอนทิตีหลักและลูกในธุรกรรมกลุ่มเอนทิตีหรือไม่

หลังจากอ่านเกี่ยวกับแนวคิด/ทฤษฎีของ Google Datastore ฉันก็เริ่มใช้ แพ็คเกจ Go datastore

สถานการณ์: ประเภท User และ LinkedAccount กำหนดให้ผู้ใช้ทุกคนมีบัญชีที่เชื่อมโยงตั้งแต่หนึ่งบัญชีขึ้นไป (ใช่ การเข้าสู่ระบบของบุคคลที่สาม) เพื่อความสอดคล้องที่แข็งแกร่ง LinkedAccounts จะเป็นลูกของผู้ใช้ที่เกี่ยวข้อง การสร้างผู้ใช้ใหม่จะเกี่ยวข้องกับการสร้างทั้งผู้ใช้และบัญชีที่เชื่อมโยง ไม่ใช่เพียงบัญชีเดียว

การสร้างผู้ใช้ดูเหมือนเป็นกรณีการใช้งานที่สมบูรณ์แบบสำหรับการทำธุรกรรม ถ้าบอกว่าการสร้าง LinkedAccount ล้มเหลว ธุรกรรมจะย้อนกลับและล้มเหลว ดูเหมือนจะเป็นไปไม่ได้ในขณะนี้ เป้าหมายคือการสร้างผู้ปกครองและลูกภายในธุรกรรม

ตามเอกสาร

การดำเนินการ Datastore ทั้งหมดในธุรกรรมจะต้องดำเนินการกับเอนทิตีในกลุ่มเอนทิตีเดียวกัน หากธุรกรรมนั้นเป็นธุรกรรมกลุ่มเดียว

เราต้องการให้ User และ LinkedAccount ใหม่อยู่ในกลุ่มเดียวกัน ดังนั้นสำหรับฉันดูเหมือนว่า Datastore น่าจะสนับสนุนสถานการณ์นี้ ความกลัวของฉันคือความหมายที่ตั้งใจไว้คือการดำเนินการกับเอนทิตี ที่มีอยู่ ในกลุ่มเดียวกันสามารถดำเนินการได้ในธุรกรรมเดียว

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 ไม่ใช่คีย์และคีย์ที่ไม่สมบูรณ์ไม่สามารถใช้เป็นพาเรนต์ได้

นี่เป็นข้อจำกัดที่จำเป็นของ Datastore หรือของไลบรารีหรือไม่ สำหรับผู้ที่มีประสบการณ์กับข้อกำหนดประเภทนี้ คุณเพียงแค่สละความสม่ำเสมอที่แข็งแกร่งและทำให้ทั้งสองประเภทเป็นสากลหรือไม่?

สำหรับความสามารถของ Google:

  • ที่เก็บข้อมูล: รหัสไม่ถูกต้อง
  • ที่เก็บข้อมูล: ไม่สามารถใช้ pendingKey เป็นประเภท *"google.golang.org/cloud/datastore".Key

person dgh    schedule 17.07.2015    source แหล่งที่มา


คำตอบ (1)


สิ่งหนึ่งที่ควรทราบก็คือธุรกรรมใน Cloud Datastore API สามารถดำเนินการกับเอนทิตีได้สูงสุด 25 รายการ กลุ่ม แต่นี่ไม่ได้ตอบคำถามเกี่ยวกับวิธีสร้างเอนทิตีสองรายการในกลุ่มเอนทิตีเดียวกันโดยเป็นส่วนหนึ่งของธุรกรรมเดียว

มีหลายวิธีในการแก้ไขปัญหานี้ (โปรดทราบว่าสิ่งนี้ใช้ได้กับการใช้งาน Cloud Datastore API ไม่ใช่แค่ไลบรารี gcloud-golang):

  1. ใช้ชื่อ (สตริง) สำหรับคีย์หลักแทนที่จะให้ Datastore กำหนดรหัสตัวเลขโดยอัตโนมัติ:

    parentKey := datastore.NewKey(ctx, "Parent", "parent-name", 0, nil)
    childKey := datastore.NewIncompleteKey(ctx, "Child", parentKey)
    
  2. ทำการเรียกอย่างชัดเจนไปที่ AllocateIds เพื่อให้ Datastore เลือกรหัสตัวเลขสำหรับคีย์หลัก:

    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 เพราะฉันต้องการให้ Datastore เลือก ID ตัวเลข แต่ข้อเสียคือ AllocateIds ไม่พร้อมใช้งานในธุรกรรม ฉันจะสำรวจแนวทางเหล่านี้แล้วกลับมา - person dgh; 18.07.2015
comment
ใช่ นั่นเป็นวิธีที่ดีในการสรุป และคุณถูกต้องว่ายังไม่รองรับในปัจจุบัน สำหรับ AllocateIds: ไม่ใช่การทำธุรกรรมในแง่ที่ว่าการจัดสรรจะไม่ถูกย้อนกลับหากธุรกรรมล้มเหลว แต่นั่นไม่ได้หยุดคุณจากการเรียกมันในขณะที่ธุรกรรมกำลังทำงานอยู่ หากธุรกรรมล้มเหลว คุณก็แค่จัดสรร ID ที่ไม่ได้ถูกใช้ ไม่ใช่เรื่องใหญ่อะไร - person Ed Davisson; 20.07.2015
comment
สุดสัปดาห์นี้ ฉันใช้วิธีการ AllocateIDs เพื่อทำธุรกรรมที่ต้องใช้คีย์ให้สมบูรณ์ และตัดสินใจว่ามันไม่น่าจะเป็นไปได้เลยที่ฉันจะต้องเรียกคืน ID ที่จัดสรรแต่ไม่ได้ใช้ เนื่องจากพื้นที่มีขนาดใหญ่มาก - person dgh; 21.07.2015