2016-04-15 109 views
1

我有两个函数:一个是将实体写入数据存储区,另一个是假设检索它们。当我在检索中使用datastore.GetAll()函数时,它不返回任何结果。我有一个测试,验证写作似乎正常工作。任何关于为什么检索不起作用的想法?golang中的datastore.GetAll没有得到结果

这里是应用程序代码:

package tracker 

import (
    "fmt" 

    "appengine" 
    "appengine/datastore" 
) 

type User struct { 
    Email string 
} 

func createUser(ctx appengine.Context, email string) (*datastore.Key, error) { 
    u := &User{ 
     Email: email, 
     } 
    incompleteKey := datastore.NewIncompleteKey(ctx, "User", nil) 
    key, err := datastore.Put(ctx, incompleteKey, u) 
    if err != nil { 
     return key, err 
    } 

    return key, nil 
} 

func getUser(ctx appengine.Context, email string) (u *User, e error) { 
    users := []User{} 
    q := datastore.NewQuery("User").Filter("Email", email) 
    keys, err := q.GetAll(ctx, &users) 
    if err != nil { 
     return nil, err 
    } 
    fmt.Printf("KEYS: %v", keys) 
    return &users[0], nil 
} 

下面是测试代码:

package tracker 

import (
    "fmt" 
    "testing" 

    "appengine/datastore" 
    "appengine/aetest" 
) 

// This test is passing. 
func TestCreateUser(t *testing.T) { 
    ctx, err := aetest.NewContext(nil) 
    if err != nil { 
     t.Fatal(err) 
    } 
    defer ctx.Close() 

    email := "[email protected]" 
    newKey, err := createUser(ctx, email) 
    if err != nil { 
     t.Errorf("Failed to create a new user: %v", err) 
    } 

    u := User{} 
    datastore.Get(ctx, newKey, &u) 

    if u.Email != email { 
     t.Errorf("Expected email to be %s, found %v.", email, u.Email) 
    } 
} 

func TestGetUser(t *testing.T) { 
    ctx, err := aetest.NewContext(nil) 
    if err != nil { 
     t.Fatal(err) 
    } 
    defer ctx.Close() 

    email := "[email protected]" 
    newKey, err := createUser(ctx, email) 
    fmt.Printf("key, %v; ", newKey) 
    u, err := getUser(ctx, newKey) 
    fmt.Printf("user, %v; error: %s", u, err) 

    if u.Email != email { 
     t.Error("Expected email to be %s, found %v.", email, u.Email) 
    } 
} 

回答

5

datastore.GetAll()不返回结果给你,因为与查询最终一致性适用。 SDK模拟最终的一致性,不会立即向您返回新保存的实体。

但在你TestCreateUser()方法,当您使用datastore.Get(),将返回保存即使是新(“刚才”)的实体,因为它是一个查找的关键,他们是强一致

幕后发生的事情是,当您拨打datastore.Put()时,保存了实体数据(属性值)并对其键进行了索引,然后返回,并且其他属性和组合索引的索引被异步更新。背景”。因此,如果您尝试执行使用索引来查找/列出实体的查询(您正在查询Email属性),那么该查询将不会看到(不会包含)新实体,直到它们被正确编入索引。当您执行datastore.Get()时,它会通过其密钥加载实体,而不是通过其他(非密钥属性或复合)索引加载实体,因此通过密钥获取实体将立即看到新实体(在返回datastore.Put()之后)。

如果你想在本地环境中测试这一点,你可以创建将用于创建新的上下文实例时提供StronglyConsistentDatastore选项,如:

inst, err := aetest.NewInstance(&aetest.Options{StronglyConsistentDatastore: true}) 
if err != nil { 
    t.Fatalf("Failed to create instance: %v", err) 
} 
defer inst.Close() 

req, err := inst.NewRequest("GET", "/", nil) 
if err != nil { 
    t.Fatalf("Failed to create req: %v", err) 
} 
ctx := appengine.NewContext(req) 

还要注意的是,如果你使用睡眠(例如time.Sleep(time.Millisecond * 500)),datastore.GetAll()也会返回新的实体,但上面的选项是测试这个的正确方法。

有许多类似的问题(+答案),阅读更多细节:

Google App Engine Datastore - Testing Queries fails

How to filter a GAE query?

Google app engine datastore query with cursor won't iterate all items

+0

感谢那些工作就像一个魅力! – katkinson

+1

@katkinson由于它的工作原因,要做的恰当事情是通过点击左侧旁边的复选标记来将答案标记为已接受。 http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work这让未来的读者知道答案可以解决问题。 – sberry