Go语言中表示SQL表的结构体(structs)

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

Go structs that represent SQL tables

问题

我对Go语言还不太熟悉,但我可以尝试为你提供一些帮助。在Go中,你可以使用数据库/ORM库来简化与数据库的通信。ORM(对象关系映射)库可以帮助你将对象映射到数据库表,并提供方便的方法来执行插入和更新操作,而无需编写原始的SQL语句。

在Go中,一些常用的ORM库包括GORM、XORM和SQLBoiler等。你可以选择其中一个库来帮助你简化数据库通信的过程。

以下是使用GORM库的示例代码,展示了如何定义模型、插入数据和更新数据:

import (
    "gorm.io/gorm"
    "gorm.io/driver/postgres"
)

type Patients struct {
    gorm.Model
    Name  string
    Image string
}

func InsertPatient(patient Patients) error {
    db, err := gorm.Open(postgres.Open("your-database-connection-string"), &gorm.Config{})
    if err != nil {
        return err
    }
    err = db.Create(&patient).Error
    if err != nil {
        return err
    }
    return nil
}

func UpdatePatient(patient Patients) error {
    db, err := gorm.Open(postgres.Open("your-database-connection-string"), &gorm.Config{})
    if err != nil {
        return err
    }
    err = db.Save(&patient).Error
    if err != nil {
        return err
    }
    return nil
}

在上面的代码中,我们使用GORM库定义了一个Patients结构体,并使用gorm.Model嵌入了一些常用的字段(如ID、CreatedAt、UpdatedAt等)。然后,我们定义了InsertPatientUpdatePatient函数来执行插入和更新操作。

你需要将your-database-connection-string替换为你的实际数据库连接字符串。然后,你可以在其他地方调用这些函数来插入和更新数据,而无需编写原始的SQL语句。

请注意,这只是一个示例,你可以根据自己的需求进行修改和扩展。希望对你有所帮助!

英文:

I am pretty new to Go and I am trying to find the best way to set up my db communication. Essentially I remember from my previous workplaces that in PHP you can create a class that represents a SQL table and when you need to insert data into your db you would create an object of that class with all the necessary data, call insert(), pass your object and it would insert that data into a corresponding table without you writing any SQL code, update() works in a very similar way except it would update instead of inserting. Unfortunately, I don't remember the name of that PHP framework but maybe someone knows a way to achieve something like that in Go or is it not a thing?

Lets say I have a struct:

type Patients struct {
	ID              int
	Name            string 
	Image           string    
}

Now I want to have a function that takes Patients objet as a parameter and inserts it into a patients postgres table automatically converting patient into what postgres expects:

func (patients *Patients) insert(patient Patients) {

}

And then update() would take a Patients object and basically perform this chunk of code without me writing it:

stmt := `update patients set
	name = $1,
	image = $2,
    where id = $3
`

_, err := db.ExecContext(ctx, stmt,
	patient.Name,
	patient.Image,
    patient.ID
)

答案1

得分: 3

你正在寻找一种称为ORM(对象关系映射器)的东西。在Go语言中有几种选择,但最流行的是GORM。这是一个有争议的话题,但我认为如果你是Go语言和/或数据库的新手,使用ORM是一个不错的选择。它可以节省你很多时间和精力。

另一种选择是使用database/sql包并编写自己的SQL查询语句。如果你是经验丰富的Go开发人员和/或数据库管理员,这是一个不错的选择。它可以让你更好地控制查询,并且更高效。推荐阅读:https://www.alexedwards.net/blog/organising-database-access。这种方法推荐使用的库包括sqlx和pgx。

以下是将你的结构体作为GORM模型的示例:

type Patient struct {
    ID    int    `gorm:"primaryKey"`
    Name  string
    Image string
}

以下是将患者插入数据库的示例程序:

package main

import (
    "fmt"
    "gorm.io/driver/postgres"
    "gorm.io/gorm"
)

type Patient struct {
    ID    int    `gorm:"primaryKey"`
    Name  string
    Image string
}

func main() {
    dsn := "host=localhost user=postgres password=postgres dbname=postgres port=5432 sslmode=disable TimeZone=UTC"
    db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
    if err != nil {
        panic("failed to connect database")
    }

    db.AutoMigrate(&Patient{})

    patient := Patient{
        Name:  "John Smith",
        Image: "https://example.com/image.png",
    }

    result := db.Create(&patient)
    if result.Error != nil {
        panic(result.Error)
    }

    fmt.Println(patient)
}

如果你想使用sqlx,可以编写类似以下的代码:

package main

import (
    "database/sql"
    "fmt"
    "log"

    _ "github.com/lib/pq"
)

type Patient struct {
    ID    int
    Name  string
    Image string
}

func main() {
    dsn := "host=localhost user=postgres password=postgres dbname=postgres port=5432 sslmode=disable TimeZone=UTC"
    db, err := sql.Open("postgres", dsn)
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    _, err = db.Exec(`
        CREATE TABLE IF NOT EXISTS patients (
            id SERIAL PRIMARY KEY,
            name TEXT,
            image TEXT
        )
    `)
    if err != nil {
        log.Fatal(err)
    }

    patient := Patient{
        Name:  "John Smith",
        Image: "https://example.com/image.png",
    }

    _, err = db.Exec(`
        INSERT INTO patients (name, image) VALUES ($1, $2)
    `, patient.Name, patient.Image)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(patient)
}

当然,使用ORM来管理数据库模式会更加复杂。你可以使用迁移工具,但我更喜欢使用一个叫做goose的工具。它的设置可能有点麻烦,但非常强大和灵活。以下是如何使用它的示例:

package main

import (
    "fmt"
    "log"

    "github.com/pressly/goose"
    "gorm.io/driver/postgres"
    "gorm.io/gorm"
)

type Patient struct {
    ID    int    `gorm:"primaryKey"`
    Name  string
    Image string
}

func main() {
    dsn := "host=localhost user=postgres password=postgres dbname=postgres port=5432 sslmode=disable TimeZone=UTC"
    db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
    if err != nil {
        panic("failed to connect database")
    }

    goose.SetDialect("postgres")
    goose.SetTableName("schema_migrations")

    err = goose.Run("up", db.DB(), "migrations")
    if err != nil {
        log.Fatal(err)
    }

    patient := Patient{
        Name:  "John Smith",
        Image: "https://example.com/image.png",
    }

    result := db.Create(&patient)
    if result.Error != nil {
        panic(result.Error)
    }

    fmt.Println(patient)
}

其中,你的迁移目录结构如下:

migrations/
    00001_create_patients.up.sql
    00001_create_patients.down.sql

你的迁移文件内容如下:

-- 00001_create_patients.up.sql
CREATE TABLE patients (
    id SERIAL PRIMARY KEY,
    name TEXT,
    image TEXT
);
-- 00001_create_patients.down.sql
DROP TABLE patients;

希望对你有所帮助!如果有任何问题,请随时告诉我。

英文:

You are looking for something called an ORM (Object Relational Mapper). There are a few in Go, but the most popular is GORM. It's a bit of a controversial topic, but I think it's a good idea to use an ORM if you're new to Go and/or databases. It will save you a lot of time and effort.

The alternative is to use the database/sql package and write your own SQL queries. This is a good idea if you're an experienced Go developer and/or database administrator. It will give you more control over your queries and will be more efficient. Recommended reading: https://www.alexedwards.net/blog/organising-database-access. Recommended libraries for this approach include sqlx and pgx.

Here is what your struct would look like as a GORM model:

type Patient struct {
    ID              int `gorm:"primaryKey"`
    Name            string 
    Image           string    
}

And here is an example program for how to insert a patient into the database:

package main

import (
    "fmt"
    "gorm.io/driver/postgres"
    "gorm.io/gorm"
)

type Patient struct {
    ID              int `gorm:"primaryKey"`
    Name            string 
    Image           string    
}

func main() {
    dsn := "host=localhost user=postgres password=postgres dbname=postgres port=5432 sslmode=disable TimeZone=UTC"
    db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
    if err != nil {
        panic("failed to connect database")
    }

    db.AutoMigrate(&Patient{})

    patient := Patient{
        Name: "John Smith",
        Image: "https://example.com/image.png",
    }

    result := db.Create(&patient)
    if result.Error != nil {
        panic(result.Error)
    }

    fmt.Println(patient)
}

If instead you wanted to use sqlx, you would write something like this:

package main

import (
    "database/sql"
    "fmt"
    "log"

    _ "github.com/lib/pq"
)

type Patient struct {
    ID              int
    Name            string 
    Image           string    
}

func main() {
    dsn := "host=localhost user=postgres password=postgres dbname=postgres port=5432 sslmode=disable TimeZone=UTC"
    db, err := sql.Open("postgres", dsn)
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    _, err = db.Exec(`
        CREATE TABLE IF NOT EXISTS patients (
            id SERIAL PRIMARY KEY,
            name TEXT,
            image TEXT
        )
    `)
    if err != nil {
        log.Fatal(err)
    }

    patient := Patient{
        Name: "John Smith",
        Image: "https://example.com/image.png",
    }

    _, err = db.Exec(`
        INSERT INTO patients (name, image) VALUES ($1, $2)
    `, patient.Name, patient.Image)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(patient)
}

Of course, managing your database schema is a bit more complicated with an ORM. You can use migrations, but I prefer to use a tool called goose. It's a bit of a pain to set up, but it's very powerful and flexible. Here is an example of how to use it:

package main

import (
    "fmt"
    "log"

    "github.com/pressly/goose"
    "gorm.io/driver/postgres"
    "gorm.io/gorm"
)

type Patient struct {
    ID              int `gorm:"primaryKey"`
    Name            string 
    Image           string    
}

func main() {
    dsn := "host=localhost user=postgres password=postgres dbname=postgres port=5432 sslmode=disable TimeZone=UTC"
    db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
    if err != nil {
        panic("failed to connect database")
    }

    goose.SetDialect("postgres")
    goose.SetTableName("schema_migrations")

    err = goose.Run("up", db.DB(), "migrations")
    if err != nil {
        log.Fatal(err)
    }

    patient := Patient{
        Name: "John Smith",
        Image: "https://example.com/image.png",
    }

    result := db.Create(&patient)
    if result.Error != nil {
        panic(result.Error)
    }

    fmt.Println(patient)
}

where your migrations directory looks like this:

migrations/
    00001_create_patients.up.sql
    00001_create_patients.down.sql

and your migrations look like this:

-- 00001_create_patients.up.sql
CREATE TABLE patients (
    id SERIAL PRIMARY KEY,
    name TEXT,
    image TEXT
);
-- 00001_create_patients.down.sql
DROP TABLE patients;

I hope this helps! Let me know if you have any questions.

答案2

得分: 0

我认为你正在寻找的是一个ORM(对象关系映射)。ORM是一个库,它可以接收语言结构并自动处理SQL逻辑。

在Go语言中,最流行的ORM库是GORM。这是他们的主页链接:https://gorm.io/。我在生产环境中广泛使用过它,使用体验很好!

文档中有一个很好的示例,你可以看一下:https://gorm.io/docs/。

希望对你有帮助。

英文:

I think what you're looking for is an ORM. An ORM is a library that essentially does this, taking language structures and automatically handling the SQL logic for you.

The most popular library for this in Go is GORM. Here's a link to their home page: https://gorm.io/. I've used it heavily in production and it's been a good experience!

The docs have a good example of what it'll look like.

Hope this helps.

答案3

得分: 0

其他答案提到了GORM以及一些更底层的工具,如database/sqlsqlxpgx,它们都很好。

但是我确实发现了GORM和这些更底层工具存在一些问题,我在这篇文章中对我发现的这些问题进行了一些解释:

https://medium.com/better-programming/golang-sql-problems-with-existing-libraries-145a037261b8

在同一篇文章中,我还推广了我编写的一个解决方案,叫做KSQL(不是Kafka的那个),它比GORM简单得多,比database/sqlsqlxpgx强大得多,你可能会喜欢。

这个想法是为常见操作(如Insert()Update()Delete())提供一些辅助函数,但是对于其他所有操作,KSQL只需让你自己编写查询语句,因此只要了解SQL就足以使用这个库,而使用GORM之前需要学习很多关于GORM库本身的知识。

你可以在这里找到它:

https://github.com/vingarcia/ksql

这里有一个简短的示例,演示如何使用KSQL将患者插入数据库:

package main

import (
	"context"
	"fmt"

	"github.com/vingarcia/ksql"
	"github.com/vingarcia/ksql/adapters/kpgx"
)

type Patient struct {
	ID    int    `ksql:"id"`
	Name  string `ksql:"name"`
	Image string `ksql:"image"`
}

// Just a simple struct containing the table name and
// the name of the ID column or columns:
var PatientsTable = ksql.NewTable("patients", "id")

func main() {
	ctx := context.Background()
	dsn := "host=localhost user=postgres password=postgres dbname=postgres port=5432 sslmode=disable TimeZone=UTC"
	db, err := kpgx.New(ctx, dsn, ksql.Config{})
	if err != nil {
		panic("failed to connect database")
	}

	patient := Patient{
		Name:  "John Smith",
		Image: "https://example.com/image.png",
	}

	err = db.Insert(ctx, PatientsTable, &patient) // (this call will retrieve the inserted ID automatically)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%+v\n", patient) // {ID:1 Name:John Smith Image:https://example.com/image.png}
}
英文:

Other answers mention both GORM and a few lower level tools like database/sql, sqlx and pgx, which are great.

But I do see some issues with both GORM and the lower level tools, I do explain a little about these issues I see in this article:

https://medium.com/better-programming/golang-sql-problems-with-existing-libraries-145a037261b8

In this same article I am also promoting a solution I wrote called KSQL (not the Kafka one), that is a lot simpler than GORM and a lot more powerful than database/sql, sqlx and pgx, you might like it.

The idea is to offer a few helper functions for common operations like Insert(), Update() and Delete() but for everything else KSQL just let's you write the query yourself, so knowing SQL is enough to use this library, while with GORM you need to learn a lot about the GORM library itself before using it well.

You can find it here:

https://github.com/vingarcia/ksql

And here is a short example of how one would go about inserting a patient into the database using KSQL:

package main

import (
	"context"
	"fmt"

	"github.com/vingarcia/ksql"
	"github.com/vingarcia/ksql/adapters/kpgx"
)

type Patient struct {
	ID    int    `ksql:"id"`
	Name  string `ksql:"name"`
	Image string `ksql:"image"`
}

// Just a simple struct containing the table name and
// the name of the ID column or columns:
var PatientsTable = ksql.NewTable("patients", "id")

func main() {
	ctx := context.Background()
	dsn := "host=localhost user=postgres password=postgres dbname=postgres port=5432 sslmode=disable TimeZone=UTC"
	db, err := kpgx.New(ctx, dsn, ksql.Config{})
	if err != nil {
		panic("failed to connect database")
	}

	patient := Patient{
		Name:  "John Smith",
		Image: "https://example.com/image.png",
	}

	err = db.Insert(ctx, PatientsTable, &patient) // (this call will retrieve the inserted ID automatically)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%+v\n", patient) // {ID:1 Name:John Smith Image:https://example.com/image.png}
}

huangapple
  • 本文由 发表于 2023年1月26日 09:41:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/75241603.html
匿名

发表评论

匿名网友

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

确定