英文:
Generic method for retrieving list of models (structs)
问题
我正在尝试为我的服务创建基本的CRUD操作。它基于在结构体中创建的数据模型。问题是我真的不想为CRUD方法重复编写代码。例如,我定义了ModelA和ModelB作为结构体:
type ModelA struct {
ID bson.ObjectId `json:"ID,omitempty" bson:"_id,omitempty"`
Slug string `json:"slug" bson:"slug,omitempty"`
Creator string `json:"-" bson:"creator,omitempty"`
DefaultLanguage string `json:"defaultLanguage" bson:"defaultLanguage,omitempty"`
}
type ModelB struct {
ID bson.ObjectId `json:"ID,omitempty" bson:"_id,omitempty"`
Type string `json:"type" bson:"type,omitempty"`
}
我想要创建一个通用的方法,用于检索给定模型的数组。对我来说,使用模型是很重要的。我可以使用纯粹的interface{}
类型快速完成,但会失去模型的功能,例如在JSON输出中隐藏某些属性(例如ModelA.Creator
)。
到目前为止,我已经为创建新数据和检索单个模型创建了通用方法。以下是示例代码:
// GET: /modelsa/{:slug}
func (r *Routes) GetModelA(w rest.ResponseWriter, req *rest.Request) {
// 将模型设置为ModelA
var model models.ModelA
r.GetBySlug(w, req, &model, "models")
}
// GET: /modelsb/{:slug}
func (r *Routes) GetModelB(w rest.ResponseWriter, req *rest.Request) {
// 将模型设置为ModelB
var model models.ModelB
r.GetBySlug(w, req, &model, "models")
}
func (r *Routes) GetBySlug(w rest.ResponseWriter, req *rest.Request, m interface{}, collection string) {
slug := req.PathParam("slug")
if err := r.GetDocumentBySlug(slug, collection, m, w, req); err != nil {
rest.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteJson(m)
}
GetModelA
和GetModelB
是路由处理程序,它们使用通用方法GetBySlug
返回由给定模型格式化的JSON。
我想要做同样的事情,但是使用给定模型的数组。到目前为止,我遇到了将结果转换为结构体的问题:
// GET /modelsa/
func (r *Routes) GetModels(w rest.ResponseWriter, req *rest.Request) {
// 在这种情况下,我认为我不需要传递一个结构体数组
// 因为给定的结构体只是一个引用。也可以是:
// var result models.ModelA。将其转换为数组可以在GetList()方法中完成
var result []models.ModelA
r.GetList(w, req, &result, "models")
}
func (r *Routes) GetList(w rest.ResponseWriter, req *rest.Request, res interface{}, col string) {
}
我无法将res
参数设置为interface{}
的数组。如果我尝试在GetList()
方法中将结果转换为[]interface{}
,然后无法将其转换为res
参数,因为它不是一个数组。
有没有一种好的方法来做到这一点?也许我想错了,应该重新设计这些方法?任何建议都将不胜感激。
英文:
I'm trying to create basic CRUD for my service. It is based on data models created in structs. The problem is that I really dont want to repeat code for CRUD methods. For example I have ModelA and ModelB defined as structs:
type ModelA struct {
ID bson.ObjectId `json:"ID,omitempty" bson:"_id,omitempty"`
Slug string `json:"slug" bson:"slug,omitempty"`
Creator string `json:"-" bson:"creator,omitempty"`
DefaultLanguage string `json:"defaultLanguage" bson:"defaultLanguage,omitempty"`
}
type ModelB struct {
ID bson.ObjectId `json:"ID,omitempty" bson:"_id,omitempty"`
Type string `json:"type" bson:"type,omitempty"`
}
What I want is to make generic method which retrieves an array of given model. It is important for me to use models. I can do it quick with pure interface{}
types but will loose model functionality, for example hiding some properties in JSON output (ex. ModelA.Creator
).
So far I've created generic methods for creating new data and retrieving single model. Here is example code:
// GET: /modelsa/{:slug}
func (r *Routes) GetModelA(w rest.ResponseWriter, req *rest.Request) {
// set model as ModelA
var model models.ModelA
r.GetBySlug(w, req, &model, "models")
}
// GET: /modelsb/{:slug}
func (r *Routes) GetModelB(w rest.ResponseWriter, req *rest.Request) {
// set model as ModelB
var model models.ModelB
r.GetBySlug(w, req, &model, "models")
}
func (r *Routes) GetBySlug(w rest.ResponseWriter, req *rest.Request, m interface{}, collection string) {
slug := req.PathParam("slug")
if err := r.GetDocumentBySlug(slug, collection, m, w, req); err != nil {
rest.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteJson(m)
}
GetModelA
and GetModelB
are route handlers which uses generic method GetBySlug
that returns a JSON formatted by given model.
I want to do the same but with the array of given models. So far I ve got problem to cast the result into the struct:
// GET /modelsa/
func (r *Routes) GetModels(w rest.ResponseWriter, req *rest.Request) {
// I think in this case I don't have to pass an array of struct
// because the given struct is only reference. It could be:
// var result models.ModelA as well. Converting it into array could
// be done in GetList() method
var result []models.ModelA
r.GetList(w, req, &result, "models")
}
func (r *Routes) GetList(w rest.ResponseWriter, req *rest.Request, res interface{}, col string) {
}
I cant set res
argument as an array of interface{}. Also I if i try to cast result to the []interface{}
within GetList()
method, I cant then cast it to the res
argument as it is not an array.
Is there a nice way to do this? Maybe I think wrong and should redesign the methods? Any advice would be appreciated.
答案1
得分: 1
你可以声明新的类型来表示你的模型的切片。例如,
type ModelAList []ModelA
type ModelBList []ModelB
然后,当你将这些新类型的变量传递给r.GetDocumentBySlug()
时,encoding/json
包中的函数将相应地解组切片。
英文:
You can declare new types which represent slice of your models. For example,
type ModelAList []ModelA
type ModelBList []ModelB
Then when you pass variables of these new types into your r.GetDocumentBySlug()
, the functions in the encoding/json
package will unmarshal the slices accordingly.
You can find working examples here (marshaling) and here (unmarshaling).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论