事先注意:
有2个API。具有导入路径的那个
appengine/datastore使用通道作为参数。具有导入路径的另一个
google.golang.org/appengine/datastore使用切片。根据您的情况调整以下示例。
具有动态属性的实体的关键是
PropertyLoadSaver接口。通过实现此接口,您可以在保存时动态地构造要保存的实体的属性。
同样,不必自己执行此操作,Go
AppEngine平台提供了一种
PropertyList类型,该类型基本上是属性列表(切片),
Property并且也实现了
PropertyLoadSaver。
因此Go中的Expando模型为
PropertyList。只需添加您希望实体拥有的属性,然后保存该
PropertyList值即可。
这是一个例子:
c := appengine.NewContext(r)props := datastore.PropertyList{ datastore.Property{Name: "time", Value: time.Now()}, datastore.Property{Name: "email", Value: "me@myhost.com"},}k := datastore.NewIncompleteKey(c, "DynEntity", nil)key, err := datastore.Put(c, k, &props)c.Infof("%v %v", key, err)本示例将保存一个
"DynEntity"具有2个动态属性的实体:
"time"和
"email"。
由于
PropertyList类型是切片,因此您还可以使用内置
append()函数为其添加属性,因此也可以
props像这样进行初始化:
var props datastore.PropertyListprops = append(props, datastore.Property{Name:"time", Value: time.Now()})props = append(props, datastore.Property{Name:"email", Value: "me@myhost.com"})将map
变成动态实体
该
PropertyLoadSaver界面并不复杂,我们可以实现它自己。在以下示例中,我在一个简单的自定义类型上实现了它
map:
type DynEnt map[string]interface{}func (d *DynEnt) Load(props []datastore.Property) error { // Note: you might want to clear current values from the map or create a new map for _, p := range props { (*d)[p.Name] = p.Value } return nil}func (d *DynEnt) Save() (props []datastore.Property, err error) { for k, v := range *d { props = append(props, datastore.Property{Name: k, Value: v}) } return}这是使用通道而不是切片的“旧”接口的实现的样子:
type DynEnt map[string]interface{}func (d *DynEnt) Load(ch <-chan datastore.Property) error { // Note: you might want to clear current values from the map or create a new map for p := range ch { // Read until channel is closed (*d)[p.Name] = p.Value } return nil}func (d *DynEnt) Save(ch chan<- datastore.Property) error { defer close(ch) // Channel must be closed for k, v := range *d { ch <- datastore.Property{Name: k, Value: v} } return nil}现在,我们可以
DynEnt像Go中的任何其他地图一样使用我们的类型,并且由于它实现了
PropertyLoadSaver,因此可以将其保存为实体(并且可以将
任何 实体加载到其中):
c := appengine.NewContext(r)d := DynEnt{"email": "me@myhost.com", "time": time.Now()}k := datastore.NewIncompleteKey(c, "DynEntity", nil)key, err := datastore.Put(c, k, &d)c.Infof("%v %v", key, err)


