Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
GORM è un popolare ORM per Go che supporta SQL Server attraverso il dialetto gorm.io/driver/sqlserver, che utilizza internamente go-mssqldb. GORM gestisce differenze di schema, generazione di query e mappatura dei tipi, così puoi lavorare con le struct Go invece di scrivere SQL grezzo.
Questo articolo tratta i pattern GORM specifici di SQL Server. Per l'uso generale di GORM, consulta la documentazione GORM.
Gli esempi in questo articolo vengono confrontati con il database di esempio AdventureWorks2025 .
Installa GORM e il dialetto di SQL Server
Crea o apri un modulo Go, poi aggiungi GORM e il dialetto di 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
Connessione a SQL Server
Apri una sessione GORM passando un DSN sqlserver:// al dialetto:
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")
}
Il dialetto usa il driver go-mssqldb dietro le quinte, quindi tutte le opzioni di connessione di Stringhe di connessione e Opzioni di connessione valgono anche per il DSN.
Mappare i modelli su tabelle esistenti
La convenzione di denominazione predefinita di GORM utilizza nomi di tabelle minuscole plurali (ad esempio, products), che non corrispondono alle convenzioni di SQL Server. Usa il TableName() metodo per associare un modello a una tabella già qualificata per lo schema:
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"
}
Tip
Definisci TableName() sempre quando lavori con i database SQL Server esistenti. Affidarsi all'autopluralizzazione di GORM porta a errori di "nome oggetto non valido" contro tabelle che seguono le convenzioni di denominazione di SQL Server.
Dati di query
Dopo aver definito un modello, usa i metodi di query di GORM per leggere i dati:
Trova righe con una clausola WHERE
Filtrare, ordinare e limitare i risultati 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)
}
Recupero di una singola riga
Usa First con una condizione per caricare un record:
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)
Contare righe
Usa Count su un telescopio modello per ottenere un conteggio delle righe:
var count int64
db.Model(&Product{}).Where("ListPrice > ?", 0).Count(&count)
fmt.Printf("Products with a list price: %d\n", count)
Inserisci, aggiorna ed elimina righe
Le operazioni di scrittura utilizzano le stesse strutture del modello. Gli esempi in questa sezione sono destinati a Production.ScrapReason, quindi non modificano tabelle critiche.
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"
}
Inserisci una riga
Passa una struct popolata a Create per inserire una riga e popolare la chiave primaria generata 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)
Aggiorna una riga
Usa Model con Update per cambiare il valore di una colonna:
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)
Elimina una riga
Passa una struct con una chiave primaria popolata a 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)
Inserimento batch e limite di 2.100 parametri
SQL Server limita sp_executesql a 2.100 parametri per istruzione. L'inserimento batch di GORM genera una clausola multi-riga VALUES in cui ogni colonna consuma un parametro, così una tabella con 10 colonne raggiunge il limite di circa 210 righe per lotto.
Imposta CreateBatchSize nella sessione per rimanere entro il 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)
}
Per tabelle con molte colonne, ridurre proporzionalmente la dimensione del batch. Una formula sicura: batch size = floor(2100 / number of inserted columns).
Transactions
Incapsula più operazioni in una transazione 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 il callback restituisce un errore, GORM torna automaticamente indietro.
SQL grezzo di riserva
Quando il query builder di GORM non genera la sintassi SQL Server di cui hai bisogno, passa a SQL grezzo continuando a usare la sessione 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)
}
Le query grezze usano lo stesso pool di connessione gestito da GORM, quindi le impostazioni del db.DB() pool da si applicano ancora.
Configura il pool di connessione
Accedi al sottostante *sql.DB per impostare i parametri del pool:
sqlDB, err := db.DB()
if err != nil {
log.Fatal(err)
}
sqlDB.SetMaxOpenConns(25)
sqlDB.SetMaxIdleConns(10)
sqlDB.SetConnMaxLifetime(5 * time.Minute)
Per indicazioni sul dimensionamento del pool, vedi pool di connessioni.
Considerazioni sull'AutoMigrate
AutoMigrate Crea o modifica tabelle per adattarle alle definizioni del tuo modello. Funziona con SQL Server, ma tieni presente questi comportamenti:
-
AutoMigrateCrea tabelle nello schema predefinito (dbo) a meno che tu non sovrascrivaTableName()con un prefisso schema. - Aggiunge colonne mancanti e crea indici, ma non elimina colonne né cambia tipi di colonne esistenti.
- SQL Server ha un limite di 128 caratteri per i nomi degli indici. I nomi degli indici generati da GORM possono superare questo limite su tabelle con nomi lunghi o indici compositi. Usa tag espliciti
gorm:"index:idx_short_name"se raggiungi questo limite.
Per i database di produzione con schemi gestiti, preferisci gli strumenti di migrazione rispetto a AutoMigrate.