Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
GORM est un ORM populaire pour Go qui prend en charge SQL Server via le dialecte gorm.io/driver/sqlserver, qui utilise go-mssqldb en interne. GORM gère les différences de schéma, la génération de requêtes et le mappage de types afin que vous puissiez travailler avec des structs Go au lieu d’écrire du SQL brut.
Cet article traite des schémas GORM spécifiques à SQL Server. Pour une utilisation générale de GORM, consultez la documentation GORM.
Les exemples de cet article s’exécutent sur la base de données d’exemple AdventureWorks2025.
Installez GORM et le dialecte SQL Server
Créez ou ouvrez un module Go, puis ajoutez GORM et le dialecte 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
Se connecter à SQL Server
Ouvrez une session GORM en transmettant un DSN sqlserver:// au dialecte :
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")
}
Le dialecte s’appuie en interne sur le pilote go-mssqldb, donc toutes les options de connexion décrites dans Chaînes de connexion et Options de connexion s’appliquent au DSN.
Associer les modèles aux tables existantes
La convention de nommage par défaut de GORM utilise des noms de tables pluriels minuscules (par exemple, products), ce qui ne correspond pas aux conventions de SQL Server. Utilisez la TableName() méthode pour lier un modèle à une table existante qualifiée par le schéma :
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
Définissez TableName() toujours quand vous travaillez avec des bases de données SQL Server existantes. Se fier à l'auto-pluralisation de GORM entraîne des erreurs de « nom d'objet invalide » sur les tables suivant les conventions de nommage de SQL Server.
Rechercher des données
Après avoir défini un modèle, utilisez les méthodes de requête de GORM pour lire les données :
Trouvez des lignes avec une clause WHERE
Filtrez, triez et limitez les résultats en utilisant Where, Order, et 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)
}
Récupérer une seule ligne
À utiliser First avec une condition pour charger un enregistrement :
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)
Compter les lignes
Utilisez Count sur une portée de modèle pour obtenir le nombre de lignes :
var count int64
db.Model(&Product{}).Where("ListPrice > ?", 0).Count(&count)
fmt.Printf("Products with a list price: %d\n", count)
Insérer, mettre à jour et supprimer les lignes
Les opérations d’écriture utilisent les mêmes structures de modèle. Les exemples de cette section ciblent Production.ScrapReason afin de ne pas modifier les tables critiques.
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"
}
Insérer une ligne
Passez une structure remplie à Create pour insérer une ligne et remplissez la clé primaire générée automatiquement :
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)
Mettre à jour une ligne
Utilisez Model avec Update pour changer la valeur d’une colonne :
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)
Supprimer une ligne
Passons une structure avec une clé primaire remplie vers 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)
Insertion par lots et la limite de 2 100 paramètres
SQL Server limite sp_executesql à 2 100 paramètres par instruction. L’insert batch de GORM génère une clause multi-lignes VALUES où chaque colonne consomme un paramètre, de sorte qu’une table de 10 colonnes atteint la limite d’environ 210 lignes par lot.
Définissez CreateBatchSize pour la session afin de rester dans la limite autorisée :
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)
}
Pour les tables avec plusieurs colonnes, réduisez proportionnellement la taille du lot. Une formule sûre : batch size = floor(2100 / number of inserted columns).
Transactions
Encapsulez plusieurs opérations dans une transaction 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")
Si le rappel renvoie une erreur, GORM revient automatiquement en arrière.
Secours SQL brut
Lorsque le constructeur de requêtes de GORM ne génère pas la syntaxe SQL Server dont vous avez besoin, passez à SQL brut tout en utilisant toujours la session 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)
}
Les requêtes brutes utilisent le même pool de connexions géré par GORM, donc les paramètres du pool de db.DB() s’appliquent toujours.
Configurez le pool de connexions
Accédez à la base *sql.DB pour définir les paramètres du pool :
sqlDB, err := db.DB()
if err != nil {
log.Fatal(err)
}
sqlDB.SetMaxOpenConns(25)
sqlDB.SetMaxIdleConns(10)
sqlDB.SetConnMaxLifetime(5 * time.Minute)
Pour des conseils sur le dimensionnement du pool de connexions, voir pool de connexions.
Considérations relatives à AutoMigrate
AutoMigrate crée ou modifie des tables pour correspondre aux définitions de votre modèle. Il fonctionne avec SQL Server, mais soyez conscient de ces comportements :
-
AutoMigratecrée des tables dans le schéma par défaut (dbo), à moins de redéfinirTableName()en le préfixant par un schéma. - Il ajoute des colonnes manquantes et crée des indices mais ne supprime pas de colonnes ni ne modifie les types de colonnes existants.
- SQL Server a une limite de 128 caractères pour les noms d’index. Les noms d’index générés par GORM peuvent dépasser cette limite sur les tables avec des noms longs ou des index composites. Utilisez des tags explicites
gorm:"index:idx_short_name"si vous atteignez cette limite.
Pour les bases de données de production avec schémas gérés, il faut privilégier les outils de migration à AutoMigrate.