英文:
Google App Engine Golang datastore.Query.GetAll not working locally
问题
我是新手使用Google App Engine,并且在使用datastore时遇到了一些问题。
我编写了一个名为GaeDatastore_test.go的测试文件,用于测试datastore.Query.GetAll方法,代码如下:
package persist
import (
"fmt"
"testing"
"appengine/aetest"
"appengine/datastore"
)
type Mock struct {
Name string
}
func TestAll(t *testing.T) {
ctx, _ := aetest.NewContext(nil)
defer ctx.Close()
d := &Mock{
"hello",
}
fmt.Println(datastore.Put(ctx, datastore.NewIncompleteKey(ctx, "test", nil), d))
fmt.Println(datastore.Put(ctx, datastore.NewIncompleteKey(ctx, "test", nil), d))
fmt.Println(datastore.Put(ctx, datastore.NewIncompleteKey(ctx, "test", nil), d))
q := datastore.NewQuery("test")
var ms []Mock
q.GetAll(ctx, &ms)
fmt.Printf("%#v", ms)
}
当我运行这个测试文件时,使用命令goapp test
,它没有返回我存储的3个实体。
我可以看到在调用datastore.Put之后返回了key,并且我可以使用key来检索它们。但是变量ms
始终为nil。
然后我尝试使用make([]Mock,10)
来初始化ms
,但是没有太大的区别,数据仍然无法获取。
我检查了query.go源文件。在内部,它使用了loadEntity方法,该方法与Get / GetMulti使用相同,并使用append将元素添加到切片中。很奇怪ms
为什么是nil。
客户端连接到一个模拟GAE环境的Python服务器。有人可以帮忙吗?
英文:
I am new to Google App Engine and meet some problems with datastore.
I wrote a test GaeDatastore_test.go to test datastore.Query.GetAll method see below
package persist
import (
"fmt"
"testing"
"appengine/aetest"
"appengine/datastore"
)
type Mock struct {
Name string
}
func TestAll(t *testing.T) {
ctx, _ := aetest.NewContext(nil)
defer ctx.Close()
d := &Mock{
"hello",
}
fmt.Println(datastore.Put(ctx, datastore.NewIncompleteKey(ctx, "test", nil), d))
fmt.Println(datastore.Put(ctx, datastore.NewIncompleteKey(ctx, "test", nil), d))
fmt.Println(datastore.Put(ctx, datastore.NewIncompleteKey(ctx, "test", nil), d))
q := datastore.NewQuery("test")
var ms []Mock
q.GetAll(ctx, &ms)
fmt.Printf("%#v", ms)
}
When I run the test file using
> goapp test
it does not return the 3 entities I have stored.
I could see key returned after calling datastore.Put and I could use datastore.Get to retrieve them using the key. But the 'ms' is always nil.
Then I tried to initialise ms using
> make([]Mock,10)
But it does not make much difference and the data still not coming through.
I checked query.go source file . Internally it uses loadEntity which is the same method used by Get / GetMulti and use append to push elements to the slice. It is quite weird that the ms is nil.
The client is connecting to a Python server simulating GAE env. Could some one help?
答案1
得分: 8
我相信这是因为你正在进行跨组查询,并且写操作尚未应用到数据存储中。开发服务器模拟了类似生产环境的写入可见性。当你不在事务或实体组中时,查询不会立即显示结果。
根据文档,
写操作在提交阶段后立即返回,然后异步进行应用阶段。
还有,
...当发生以下情况之一时,应用阶段将被完全执行:
定期的 Datastore 扫描检查未完成的提交作业并应用它们。使用受影响实体组的某些操作(get、put、delete 和祖先查询)会导致已提交但尚未应用的任何更改在继续执行新操作之前完成。
还有,
因为 Datastore 的 get 和祖先查询在执行之前会应用任何未完成的修改,所以这些操作总是能够看到所有先前成功事务的一致视图。这意味着 get 操作(通过其键查找更新的实体)保证能够看到该实体的最新版本。
关于这些引用的来源以及有关写入和数据可见性规则的更多详细信息,请参阅:https://developers.google.com/appengine/docs/go/datastore/#Go_Datastore_writes_and_data_visibility
以下是修改后的代码版本,在每次 put 操作后对返回的键执行 Get()。Get() 强制应用该键。这样可以确保你的 GetAll 查询将返回所有测试实体。
package persist
import (
"fmt"
"testing"
"appengine/aetest"
"appengine/datastore"
)
type Mock struct {
Name string
}
func TestAll(t *testing.T) {
ctx, _ := aetest.NewContext(nil)
defer ctx.Close()
d := &Mock{
"hello",
}
for i := 0; i < 3; i++ {
k, err := datastore.Put(ctx, datastore.NewIncompleteKey(ctx, "test", nil), d)
fmt.Println(k, err)
datastore.Get(ctx, k, nil)
}
q := datastore.NewQuery("test")
var ms []Mock
q.GetAll(ctx, &ms)
fmt.Printf("%#v", ms)
}
英文:
I believe it to be because you are doing a cross group query and the write has not been applied to the data store yet. The dev server simulates production-like write visibility. When you are not in a transaction or entity group, queries will not show results right away.
From the docs,
> The write operation returns immediately after the Commit phase and the Apply phase then takes place asynchronously.
and,
> ... Apply is rolled forward to completion when one of the following
> occurs:
>
> Periodic Datastore sweeps check for uncompleted Commit jobs and apply
> them. Certain operations (get, put, delete, and ancestor queries) that
> use the affected entity group cause any changes that have been
> committed but not yet applied to be completed before proceeding with
> the new operation.
and,
> Because Datastore gets and ancestor queries apply any outstanding
> modifications before executing, these operations always see a
> consistent view of all previous successful transactions. This means
> that a get operation (looking up an updated entity by its key) is
> guaranteed to see the latest version of that entity.
For the source of these quotes and much more detail on writes and data visibility rules see: https://developers.google.com/appengine/docs/go/datastore/#Go_Datastore_writes_and_data_visibility
Here is a modified version of your code that performs a Get on the returned key after each put. A Get() forces that key to be applied. This ensure that your GetAll query will return all your test entities.
package persist
import (
"fmt"
"testing"
"appengine/aetest"
"appengine/datastore"
)
type Mock struct {
Name string
}
func TestAll(t *testing.T) {
ctx, _ := aetest.NewContext(nil)
defer ctx.Close()
d := &Mock{
"hello",
}
for i := 0; i < 3; i++ {
k, err := datastore.Put(ctx, datastore.NewIncompleteKey(ctx, "test", nil), d)
fmt.Println(k, err)
datastore.Get(ctx, k, nil)
}
q := datastore.NewQuery("test")
var ms []Mock
q.GetAll(ctx, &ms)
fmt.Printf("%#v", ms)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论