我想做类似Python在应用程序引擎上支持的Expando模型的事情。
有时您不想提前声明属性。特殊的模型子类Expando更改其实体的行为,以便将分配的所有属性(只要它不以下划线开头)都保存到数据存储区。
如何在Go中执行此操作?
事先注意:
有2个API。具有导入路径的那个appengine/datastore
使用通道作为参数。具有导入路径的另一个google.golang.org/appengine/datastore
使用切片。根据您的情况调整以下示例。有关详细信息,请参见此问题:如何正确导入Golang appengine?
具有动态属性的实体的关键是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: "[email protected]"},
}
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.PropertyList
props = append(props, datastore.Property{Name:"time", Value: time.Now()})
props = append(props, datastore.Property{Name:"email", Value: "[email protected]"})
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": "[email protected]", "time": time.Now()}
k := datastore.NewIncompleteKey(c, "DynEntity", nil)
key, err := datastore.Put(c, k, &d)
c.Infof("%v %v", key, err)
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句