Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
GORM é um ORM popular de Go que oferece suporte ao SQL Server por meio do dialeto gorm.io/driver/sqlserver, que usa go-mssqldb internamente. O GORM lida com diferenças de esquema, geração de consultas e mapeamento de tipos para que você possa trabalhar com structs do Go em vez de escrever SQL bruto.
Este artigo aborda padrões GORM específicos do SQL Server. Para uso geral do GORM, veja a documentação do GORM.
Os exemplos neste artigo usam o banco de dados de exemplo AdventureWorks2025.
Instalar o GORM e o dialeto do SQL Server
Crie ou abra um módulo Go, depois adicione o GORM e o dialeto do SQL Server:
mkdir go-gorm-sqlserver
cd go-gorm-sqlserver
go mod init example.com/go-gorm-sqlserver
go get gorm.io/gorm
go get gorm.io/driver/sqlserver
Conectar-se ao SQL Server
Abra uma sessão do GORM passando um DSN sqlserver:// ao dialeto:
package main
import (
"fmt"
"log"
"gorm.io/driver/sqlserver"
"gorm.io/gorm"
)
func main() {
// Replace <server>, <user>, and <password> with your own values.
// In production, load credentials from environment variables or a secret store.
dsn := "sqlserver://<user>:<password>@<server>.database.windows.net:1433?database=AdventureWorks2025&encrypt=true&TrustServerCertificate=false"
db, err := gorm.Open(sqlserver.Open(dsn), &gorm.Config{})
if err != nil {
log.Fatal(err)
}
sqlDB, err := db.DB()
if err != nil {
log.Fatal(err)
}
defer sqlDB.Close()
fmt.Println("Connected to SQL Server with GORM")
}
O dialeto usa internamente o driver go-mssqldb, então todas as opções de conexão de Cadeias de conexão e Opções de conexão se aplicam ao DSN.
Mapear modelos para tabelas existentes
A convenção padrão de nomes do GORM usa nomes de tabelas plurais minúsculas (por exemplo, products), que não correspondem às convenções do SQL Server. Use o método TableName() para vincular um modelo a uma tabela existente qualificada por esquema:
type Product struct {
ProductID int32 `gorm:"column:ProductID;primaryKey"`
Name string `gorm:"column:Name"`
ProductLine *string `gorm:"column:ProductLine"`
ListPrice float64 `gorm:"column:ListPrice"`
}
func (Product) TableName() string {
return "Production.Product"
}
Dica
Sempre defina TableName() quando você trabalha com bancos de dados SQL Server existentes. Confiar na pluralização automática do GORM resulta em erros de "nome de objeto inválido" em tabelas que seguem as convenções de nomenclatura do SQL Server.
Consultar dados
Depois de definir um modelo, use os métodos de consulta do GORM para ler dados:
Encontre linhas com uma cláusula WHERE
Filtre, ordene e limite os resultados usando Where, Order, e Limit:
var products []Product
result := db.Where("ListPrice > ?", 1000).
Order("ListPrice DESC").
Limit(5).
Find(&products)
if result.Error != nil {
log.Fatal(result.Error)
}
for _, p := range products {
fmt.Printf("%-35s $%.2f\n", p.Name, p.ListPrice)
}
Recuperar uma única linha
Use First com uma condição para carregar um registro:
var product Product
if err := db.First(&product, "ProductID = ?", 680).Error; err != nil {
log.Fatal(err)
}
fmt.Printf("%s: $%.2f\n", product.Name, product.ListPrice)
Contar linhas
Use Count em um escopo de modelo para obter uma contagem de linhas:
var count int64
db.Model(&Product{}).Where("ListPrice > ?", 0).Count(&count)
fmt.Printf("Products with a list price: %d\n", count)
Inserir, atualizar e excluir linhas
Operações de escrita usam as mesmas estruturas de modelo. Os exemplos nesta seção apontam para Production.ScrapReason para que não modifiquem tabelas críticas.
type ScrapReason struct {
ScrapReasonID int16 `gorm:"column:ScrapReasonID;primaryKey;autoIncrement"`
Name string `gorm:"column:Name"`
ModifiedDate time.Time `gorm:"column:ModifiedDate"`
}
func (ScrapReason) TableName() string {
return "Production.ScrapReason"
}
Insira uma linha
Passe uma estrutura preenchida para Create inserir uma linha e preencha a chave primária gerada automaticamente:
reason := ScrapReason{Name: "GORM test scrap", ModifiedDate: time.Now()}
if err := db.Create(&reason).Error; err != nil {
log.Fatal(err)
}
fmt.Printf("Inserted ScrapReasonID: %d\n", reason.ScrapReasonID)
// Clean up
db.Delete(&reason)
Atualizar uma linha
Use Model com Update para alterar o valor de uma coluna:
reason := ScrapReason{Name: "GORM update test", ModifiedDate: time.Now()}
db.Create(&reason)
db.Model(&reason).Update("Name", "GORM updated scrap")
var updated ScrapReason
db.First(&updated, reason.ScrapReasonID)
fmt.Printf("Updated name: %s\n", updated.Name)
// Clean up
db.Delete(&reason)
Excluir uma linha
Passe uma estrutura com uma chave primária preenchida para Delete:
reason := ScrapReason{Name: "GORM delete test", ModifiedDate: time.Now()}
db.Create(&reason)
id := reason.ScrapReasonID
db.Delete(&reason)
var count int64
db.Model(&ScrapReason{}).Where("ScrapReasonID = ?", id).Count(&count)
fmt.Printf("Rows remaining with that ID: %d\n", count)
Inserção em lote e o limite de 2.100 parâmetros
O SQL Server limita sp_executesql a 2.100 parâmetros por instrução. O inserto por lote do GORM gera uma cláusula de várias linhas VALUES onde cada coluna consome um parâmetro, então uma tabela com 10 colunas atinge o limite de aproximadamente 210 linhas por lote.
Defina CreateBatchSize na sessão para permanecer dentro do limite:
reasons := make([]ScrapReason, 50)
for i := range reasons {
reasons[i] = ScrapReason{
Name: fmt.Sprintf("Batch scrap %d", i+1),
ModifiedDate: time.Now(),
}
}
// 2 inserted columns per row (Name, ModifiedDate; the autoIncrement ID is excluded),
// so batches of 500 are well within the 2,100-parameter limit.
result := db.CreateInBatches(&reasons, 500)
if result.Error != nil {
log.Fatal(result.Error)
}
fmt.Printf("Inserted %d rows in batches\n", result.RowsAffected)
// Clean up
for _, r := range reasons {
db.Delete(&r)
}
Para tabelas com muitas colunas, reduza o tamanho do lote proporcionalmente. Uma fórmula segura: batch size = floor(2100 / number of inserted columns).
Transactions
Agrupe várias operações em uma transação do GORM:
err := db.Transaction(func(tx *gorm.DB) error {
r1 := ScrapReason{Name: "TX scrap 1", ModifiedDate: time.Now()}
if err := tx.Create(&r1).Error; err != nil {
return err
}
r2 := ScrapReason{Name: "TX scrap 2", ModifiedDate: time.Now()}
if err := tx.Create(&r2).Error; err != nil {
return err
}
// Both inserts commit together.
fmt.Printf("Inserted IDs: %d, %d\n", r1.ScrapReasonID, r2.ScrapReasonID)
// Clean up inside the same transaction.
tx.Delete(&r1)
tx.Delete(&r2)
return nil
})
if err != nil {
log.Fatal(err)
}
fmt.Println("Transaction committed")
Se o retorno de chamada retornar um erro, o GORM reverte automaticamente.
Fallback de SQL bruto
Quando o construtor de consultas do GORM não gera a sintaxe do SQL Server que você precisa, passe para SQL bruto enquanto ainda usa a sessão do GORM:
var results []struct {
Name string
ListPrice float64
}
result := db.Raw("SELECT TOP 5 Name, ListPrice FROM Production.Product WHERE ListPrice > @price ORDER BY ListPrice DESC",
sql.Named("price", 1000)).Scan(&results)
if result.Error != nil {
log.Fatal(result.Error)
}
for _, r := range results {
fmt.Printf("%-35s $%.2f\n", r.Name, r.ListPrice)
}
Consultas brutas usam o mesmo pool de conexões gerenciado pelo GORM, então as configurações do db.DB() pool ainda se aplicam.
Configure o pool de conexões
Acesse o subjacente *sql.DB para definir parâmetros do pool:
sqlDB, err := db.DB()
if err != nil {
log.Fatal(err)
}
sqlDB.SetMaxOpenConns(25)
sqlDB.SetMaxIdleConns(10)
sqlDB.SetConnMaxLifetime(5 * time.Minute)
Para orientações sobre o dimensionamento do pool de conexões, consulte Pool de conexões.
Considerações sobre AutoMigrate
AutoMigrate cria ou altera tabelas para corresponder às definições do seu modelo. Ele funciona com SQL Server, mas fique atento a estes comportamentos:
-
AutoMigratecria tabelas no esquema padrão (dbo), a menos que você substituaTableName()com um prefixo de esquema. - Ele adiciona colunas faltantes e cria índices, mas não elimina colunas nem altera tipos de colunas existentes.
- O SQL Server tem um limite de 128 caracteres para nomes de índice. Os nomes de índices gerados pelo GORM podem exceder esse limite em tabelas com nomes longos ou índices compostos. Use tags explícitas
gorm:"index:idx_short_name"caso atinja esse limite.
Para bancos de dados de produção com esquemas gerenciados, prefira ferramentas de migração a AutoMigrate.