在Google App Engine Datastore中,Go语言支持多对多关系(has-many relationship)。

huangapple go评论89阅读模式
英文:

Go has-many relationship in Google App Engine Datastore

问题

我对Go语言非常陌生,但我会尽力帮你翻译。以下是你要翻译的内容:

我对Go语言非常陌生,到目前为止我非常喜欢它。然而,我无论如何都无法弄清楚这个问题。

我有一个简单的包,名为invoice。

type Invoice struct {
    key datastore.Key
    Name string
    Created time.Time
    Updated time.Time
    lineItems []LineItem
}

一个Invoice有几个LineItem。

type LineItem struct {
    key datastore.Key
    InvoiceKey *datastore.Key
    Name string
    Description string
}

我的包中有几个函数。

func New(c appengine.Context) (i Invoice)
func (i *Invoice) Update()
func (i *Invoice) Save(c appengine.Context)
func (i *Invoice) AddLineItem(c appengine.Context, name string)

New()函数返回一个新的Invoice,并将由datastore.NewIncompleteKey()生成的键保存在Invoice中作为一个未导出的变量,以便稍后保存它。

所有这些都运行得很好,是否是正确的方法是另一个问题。我也愿意听取对此的评论。我似乎无法弄清楚的是最后一个函数。

func (i *Invoice) AddLineItem(c appengine.Context, name string) {
    key := datastore.NewIncompleteKey(c, "LineItem", &i.key)
    lineItem := LineItem{key: *key, InvoiceKey: &i.key, Name: name}
    i.lineItems = append(i.lineItems, lineItem)
}

在Save()函数中:

for _, lineItem := range i.lineItems {
    _, err := datastore.Put(c, &lineItem.key, &lineItem)
    if err != nil {
        panic(err)
    }
}

我一直在这里遇到一个无效的键错误。我基本上只是想让一个Invoice能够拥有多个LineItem。能够将它们全部保存到数据存储中,然后在需要时提取出整个Invoice和所有的LineItem。

我走在正确的轨道上吗?有更好的方法吗?

英文:

I am very new to Go and so far I am loving it. However, I can't figure this out for the life of me.

I have a simple package, invoice.

type Invoice struct {
    key datastore.Key
    Name string
    Created time.Time
    Updated time.Time
    lineItems []LineItem
}

An Invoice has several LineItems.

type LineItem struct {
	key datastore.Key
    InvoiceKey *datastore.Key
    Name string
    Description string
}

My package has a couple functions.

func New(c appengine.Context) (i Invoice)
func (i *Invoice) Update()
func (i *Invoice) Save(c appengine.Context)
func (i *Invoice) AddLineItem(c appengine.Context, name string)

New() returns a new Invoice, and saves the key generated by datastore.NewIncompleteKey() inside the Invoice as an unexported variable so that I can save it later.

All of that runs fine, whether it is the proper way to do this or not is another question. I'm open to comments on that too. What I can't seem to figure out is that last function.

func (i *Invoice) AddLineItem(c appengine.Context, name string) {
	key := datastore.NewIncompleteKey(c, "LineItem", &i.key)
	lineItem := LineItem{key: *key, InvoiceKey: &i.key, Name: name}
	i.lineItems = append(i.lineItems, lineItem)
}

And in Save()

for _, lineItem := range i.lineItems {
	_, err := datastore.Put(c, &lineItem.key, &lineItem)
	if err != nil {
		panic(err)
	}
}

I keep getting an invalid key error here. I'm basically just trying to make an Invoice have the ability to have many LineItems. Be able to save them all to the datastore, and then pull out the entire Invoice with all the LineItems as needed.

Am I on the right track? Is there a better way to do this?

答案1

得分: 0

你的 lineItems []LineItemkey datastore.Key 是未导出的,它们需要以大写字母开头,否则 GAE 将无法使用它们。

根据规范
> 为了允许从另一个包中访问,标识符必须被导出。如果满足以下两个条件,则标识符被导出:
>
> 1. 标识符名称的第一个字符是一个 Unicode 大写字母(Unicode 类别 "Lu");
> 2. 标识符在包块中声明,或者它是字段名或方法名。
>
> 所有其他标识符都不会被导出。

英文:

Your lineItems []LineItem and key datastore.Key are unexported, they need to start with a capital letter otherwise the GAE won't be able to use it.

From the specs:
> An identifier may be exported to permit access to it from another package. An identifier is exported if both:
>
> 1. the first character of the identifier's name is a Unicode upper case letter (Unicode class "Lu"); and
> 2. the identifier is declared in the package block or it is a field name or method name.
>
> All other identifiers are not exported.

答案2

得分: 0

不要使用datastore.Key,而是使用*datastore.Key。任何时候你认为它可能没有设置都是一个错误的源头,可能会将你的无效键错误转换为恐慌。

你给LineItem键设置了一个父键(即Invoice),这是可以的,但是为什么还要存储Invoice键和LineItem键呢?你可以通过调用后者的Parent方法来获取前者。

英文:

Don't use datastore.Key, use *datastore.Key instead. Any time you think it might not be set is a source of a bug, and will probably turn your invalid key errors into panics.

You are giving LineItem keys a parent (the Invoice), which is fine, but why then do you store the Invoice key in addition to the LineItem key? You can get the former by calling the latter's Parent method.

答案3

得分: 0

我遇到的问题是尝试使用不完整的发票键生成不完整的LineItem键。

key, err := datastore.Put(c, &i.key, i)

请使用put返回的完整键。

for _, lineItem := range i.lineItems {
	key := datastore.NewIncompleteKey(c, "LineItem", key)
	lineItem.InvoiceKey = k
	_, err := datastore.Put(c, key, &lineItem)
	if err != nil {
		panic(err)
	}
}

这样存储它们。现在要解决的任务是如何从数据存储中读取它们!祝我好运。

英文:

The issue I was having was trying to use an incomplete invoice key to generate an incomplete LineItem key.

key, err := datastore.Put(c, &i.key, i)

Use the complete key returned from the put.

for _, lineItem := range i.lineItems {
	key := datastore.NewIncompleteKey(c, "LineItem", key)
	lineItem.InvoiceKey = k
	_, err := datastore.Put(c, key, &lineItem)
	if err != nil {
		panic(err)
	}
}

That stores them. Now to the task of figuring out how to read them all out of the datastore! Wish me luck.

huangapple
  • 本文由 发表于 2014年7月8日 09:16:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/24622294.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定