2016-08-24 3 views
1

私は多少のMVCアーキテクチャを備えたgin-gonic Webアプリケーションを持っています。私は、モデルのカップルを作成し、それらのすべてが一つの共通の構造体を埋め込む:一般的な構造体(jsonマーシャリング)を組み込んだすべての構造体型を処理する1つのメソッド

type User struct { 
    ID int 
    Name string 
} 

type Admin struct { 
    User 
    Level int 
} 

... { 
    User 
} 

は今、私はJSON形式でデータベースに格納します。私が達成したい目標は、任意のモデルをマーシャリングしてDBに保存するという関数/メソッドを1つだけコード化することです。このメソッドは、User構造体からだけでなく、現在のモデルのすべてのフィールドをマーシャリングする必要があります。ユーザーは{id: 1, name: "zhora"}にマーシャリングする必要がありますが、管理者は{id: 1, name: "gena", level: 2}になります。このような

func (i *User) Save() { 
    data, err := json.Marshal(i) 
    check(err) 
    if i.ID == 0 { 
    _, err = app.DB.Exec(`INSERT INTO users(data) VALUES ($1) `, string(data)) 
    } else { 
    _, err = app.DB.Exec(`UPDATE users SET data = $1 WHERE id=$2`, string(data), i.ID) 
    } 
    check(err) 
} 

は今、私は唯一の方法で受信機を変更し、すべてのモデルファイルにこのfuncをコピー/ペーストする必要があります。これは避けられますか?

答えて

3

あなたはこのようなものfunc Save(d interface{})使用することができます:すべてのタイプのために、この一つの関数を使用し、あなたのケースのための

{"ID":0,"Name":""} 
{"ID":0,"Name":"","Level":0} 

func Save(i interface{}, id int) { 
    data, err := json.Marshal(i) 
    check(err) 
    if id == 0 { 
     _, err = app.DB.Exec(`INSERT INTO users(data) VALUES ($1) `, string(data)) 
    } else { 
     _, err = app.DB.Exec(`UPDATE users SET data = $1 WHERE id=$2`, string(data), id) 
    } 
    check(err) 
} 

package main 

import (
    "encoding/json" 
    "fmt" 
) 

type User struct { 
    ID int 
    Name string 
} 

type Admin struct { 
    User 
    Level int 
} 

func main() { 
    Save(User{}) 
    Save(Admin{}) 
} 

func Save(d interface{}) { 
    body, err := json.Marshal(d) 
    if err != nil { 
     panic(err) 
    } 
    st := string(body) 
    fmt.Println(st) 
} 

出力をそしてそれをこのように呼んでください:

u := User{} 
a := Admin{} 

Save(u, u.ID) 
Save(a, a.ID) 

そしてはい、これは一つでもパラメータにSaveへの呼び出しを簡素化している:

package main 

import (
    "encoding/json" 
    "fmt" 
) 

type Model interface { 
    ID() int 
    setID(int) 
} 

type User struct { 
    Id int 
    Name string 
} 

func (t User) ID() int  { return t.Id } 
func (t User) setID(id int) { t.Id = id } 

type Admin struct { 
    User 
    Level int 
} 

func main() { 
    Save(User{}) 
    Save(Admin{}) 
} 

func Save(d Model) { 
    body, err := json.Marshal(d) 
    if err != nil { 
     panic(err) 
    } 
    st := string(body) 
    fmt.Println(st) 

    fmt.Println("ID is ", d.ID()) 
} 

出力:

{"Id":0,"Name":""} 
ID is 0 
{"Id":0,"Name":"","Level":0} 
ID is 0 

あなたはこの1つの機能を使用することができますすべてのタイプ:

func Save(i Model) { 
    data, err := json.Marshal(i) 
    check(err) 
    id := i.ID() 
    if id == 0 { 
     _, err = app.DB.Exec(`INSERT INTO users(data) VALUES ($1) `, string(data)) 
    } else { 
     _, err = app.DB.Exec(`UPDATE users SET data = $1 WHERE id=$2`, string(data), id) 
    } 
    check(err) 
} 

そして、このようにそれを呼び出す:

u := User{} 
a := Admin{} 

Save(u) 
Save(a) 

Effective Go

ゲッター

Goがゲッターとセッターのための自動サポートを提供していません。 ゲッタとセッタを自分で提供するのに間違っていることは何もありません。それはしばしば ですが、getterの名前にGetを入れるのは慣用でもなくても必要ありません。所有者 (小文字、アンエクスポート)というフィールドがある場合、getterメソッドは、GetOwnerではなく、オーナー (大文字と小文字がエクスポートされた)と呼ばれる必要があります。 エクスポートに大文字の名前を使用すると、メソッドとフィールドを区別するためのフックが提供されます。セッター機能は、必要に応じてSetOwnerと呼ばれることがあります。両方の名前は、実際にも読ん :

owner := obj.Owner() 
if owner != user { 
    obj.SetOwner(user) 
} 
+0

@kakysha私はこのことができます願っています。 –

+1

ありがとうございます!非常にあなたの助けに感謝します。あなたのソリューションはうまくいきましたが、もう少し進んで、 'getID()int'と' setID(int) 'メソッドを使って' Model'インターフェースを作成しました。 'User'がこのインターフェースを満たし、' interface' {} 'をメソッド' Save(m Model) 'に渡して、第二引数としてidを渡さないようにします。また、 'INSERT ... RETURNING id'の後に渡された構造体にIDフィールドを割り当てる必要がありました。もう一度ありがとう!、あなたは私を救った! – kakysha

+1

はゲッタとセッタに関するあなたの更新を見た。 User.IDを非表示にし、getID()をID()に変更しました。もう一度ありがとうございます。何らかの理由で 'golint'はそれについて文句を言っていなかった:( – kakysha

関連する問題