Manipuler des données
Avant l’introduction de MARS (Multiple Active Result Set), les développeurs devaient utiliser soit plusieurs connexions, soit des curseurs côté serveur pour résoudre certains scénarios. En outre, quand plusieurs connexions étaient utilisées dans une situation transactionnelle, des connexions liées (avec sp_getbindtoken et sp_bindsession) étaient requises. Les scénarios suivants montrent comment utiliser une connexion compatible MARS au lieu de plusieurs connexions.
Utilisation de plusieurs commandes avec MARS
L’application Console suivante montre comment utiliser deux objets SqlDataReader avec deux objets SqlCommand et un objet SqlConnection unique avec MARS activé.
Exemple
L’exemple ouvre une connexion unique à la base de données AdventureWorks. À l’aide d’un objet SqlCommand, un SqlDataReader est créé. À mesure que le lecteur est utilisé, un deuxième SqlDataReader est ouvert, en utilisant les données du premier SqlDataReader comme entrée de la clause WHERE pour le deuxième lecteur.
Notes
L’exemple suivant utilise l’exemple de base de données AdventureWorks inclus dans SQL Server. La chaîne de connexion fournie dans l’exemple de code suppose que la base de données est installée et disponible sur l’ordinateur local. Modifiez la chaîne de connexion en fonction des besoins de votre environnement.
Option Strict On
Option Explicit On
Imports System
Imports System.Data
Imports System.Data.SqlClient
Module Module1
Sub Main()
' By default, MARS is disabled when connecting
' to a MARS-enabled host.
' It must be enabled in the connection string.
Dim connectionString As String = GetConnectionString()
Dim vendorID As Integer
Dim vendorCmd As SqlCommand
Dim productCmd As SqlCommand
Dim productReader As SqlDataReader
Dim vendorSQL As String = & _
"SELECT VendorId, Name FROM Purchasing.Vendor"
Dim productSQL As String = _
"SELECT Production.Product.Name FROM Production.Product " & _
"INNER JOIN Purchasing.ProductVendor " & _
"ON Production.Product.ProductID = " & _
"Purchasing.ProductVendor.ProductID " & _
"WHERE Purchasing.ProductVendor.VendorID = @VendorId"
Using awConnection As New SqlConnection(connectionString)
vendorCmd = New SqlCommand(vendorSQL, awConnection)
productCmd = New SqlCommand(productSQL, awConnection)
productCmd.Parameters.Add("@VendorId", SqlDbType.Int)
awConnection.Open()
Using vendorReader As SqlDataReader = vendorCmd.ExecuteReader()
While vendorReader.Read()
Console.WriteLine(vendorReader("Name"))
vendorID = CInt(vendorReader("VendorId"))
productCmd.Parameters("@VendorId").Value = vendorID
' The following line of code requires
' a MARS-enabled connection.
productReader = productCmd.ExecuteReader()
Using productReader
While productReader.Read()
Console.WriteLine(" " & CStr(productReader("Name")))
End While
End Using
End While
End Using
End Using
Console.WriteLine("Press any key to continue")
Console.ReadLine()
End Sub
Function GetConnectionString() As String
' To avoid storing the connection string in your code,
' you can retrieve it from a configuration file.
Return "..." & _
"MultipleActiveResultSets=True"
End Function
End Module
using System;
using System.Data;
using System.Data.SqlClient;
class Class1
{
static void Main()
{
// By default, MARS is disabled when connecting
// to a MARS-enabled host.
// It must be enabled in the connection string.
string connectionString = GetConnectionString();
int vendorID;
SqlDataReader productReader = null;
string vendorSQL =
"SELECT VendorId, Name FROM Purchasing.Vendor";
string productSQL =
"SELECT Production.Product.Name FROM Production.Product " +
"INNER JOIN Purchasing.ProductVendor " +
"ON Production.Product.ProductID = " +
"Purchasing.ProductVendor.ProductID " +
"WHERE Purchasing.ProductVendor.VendorID = @VendorId";
using (SqlConnection awConnection =
new SqlConnection(connectionString))
{
SqlCommand vendorCmd = new SqlCommand(vendorSQL, awConnection);
SqlCommand productCmd =
new SqlCommand(productSQL, awConnection);
productCmd.Parameters.Add("@VendorId", SqlDbType.Int);
awConnection.Open();
using (SqlDataReader vendorReader = vendorCmd.ExecuteReader())
{
while (vendorReader.Read())
{
Console.WriteLine(vendorReader["Name"]);
vendorID = (int)vendorReader["VendorId"];
productCmd.Parameters["@VendorId"].Value = vendorID;
// The following line of code requires
// a MARS-enabled connection.
productReader = productCmd.ExecuteReader();
using (productReader)
{
while (productReader.Read())
{
Console.WriteLine(" " +
productReader["Name"].ToString());
}
}
}
}
Console.WriteLine("Press any key to continue");
Console.ReadLine();
}
}
private static string GetConnectionString()
{
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file.
return "..." +
"MultipleActiveResultSets=True";
}
}
Lecture et mise à jour des données avec MARS
MARS permet l’utilisation d’une connexion pour les opérations de lecture et les opérations DML (Data Manipulation Language) avec plusieurs opérations en attente. Cette fonctionnalité évite à une application de traiter les erreurs de connexion occupée. En outre, MARS peut remplacer l’utilisateur des curseurs côté serveur, qui consomme généralement davantage de ressources. Pour finir, comme plusieurs opérations peuvent opérer sur une seule connexion, elles peuvent partager le même contexte de transaction, en éliminant la nécessité d’utiliser les procédures stockées système sp_getbindtoken et sp_bindsession.
Exemple
L’application Console suivante montre comment utiliser deux objets SqlDataReader avec trois objets SqlCommand et un objet SqlConnection unique avec MARS activé. Le premier objet de commande récupère une liste de fournisseurs dont le niveau de solvabilité est 5. Le deuxième objet de commande utilise l’ID de fournisseur fournie par un SqlDataReader pour charger le deuxième SqlDataReader avec tous les produits du fournisseur en question. Chaque enregistrement de produit est visité par le deuxième SqlDataReader. Un calcul est effectué afin de déterminer ce que doit être le nouveau OnOrderQty. Le troisième objet de commande est ensuite utilisé pour mettre à jour la table ProductVendor avec la nouvelle valeur. Tout ce processus entier se déroule au sein d’une seule transaction, qui est restaurée à la fin.
Notes
L’exemple suivant utilise l’exemple de base de données AdventureWorks inclus dans SQL Server. La chaîne de connexion fournie dans l’exemple de code suppose que la base de données est installée et disponible sur l’ordinateur local. Modifiez la chaîne de connexion en fonction des besoins de votre environnement.
Option Strict On
Option Explicit On
Imports System
Imports System.Data
Imports System.Data.SqlClient
Module Module1
Sub Main()
' By default, MARS is disabled when connecting
' to a MARS-enabled host.
' It must be enabled in the connection string.
Dim connectionString As String = GetConnectionString()
Dim updateTx As SqlTransaction
Dim vendorCmd As SqlCommand
Dim prodVendCmd As SqlCommand
Dim updateCmd As SqlCommand
Dim prodVendReader As SqlDataReader
Dim vendorID As Integer
Dim productID As Integer
Dim minOrderQty As Integer
Dim maxOrderQty As Integer
Dim onOrderQty As Integer
Dim recordsUpdated As Integer
Dim totalRecordsUpdated As Integer
Dim vendorSQL As String = _
"SELECT VendorID, Name FROM Purchasing.Vendor " & _
"WHERE CreditRating = 5"
Dim prodVendSQL As String = _
"SELECT ProductID, MaxOrderQty, MinOrderQty, OnOrderQty " & _
"FROM Purchasing.ProductVendor " & _
"WHERE VendorID = @VendorID"
Dim updateSQL As String = _
"UPDATE Purchasing.ProductVendor " & _
"SET OnOrderQty = @OrderQty " & _
"WHERE ProductID = @ProductID AND VendorID = @VendorID"
Using awConnection As New SqlConnection(connectionString)
awConnection.Open()
updateTx = awConnection.BeginTransaction()
vendorCmd = New SqlCommand(vendorSQL, awConnection)
vendorCmd.Transaction = updateTx
prodVendCmd = New SqlCommand(prodVendSQL, awConnection)
prodVendCmd.Transaction = updateTx
prodVendCmd.Parameters.Add("@VendorId", SqlDbType.Int)
updateCmd = New SqlCommand(updateSQL, awConnection)
updateCmd.Transaction = updateTx
updateCmd.Parameters.Add("@OrderQty", SqlDbType.Int)
updateCmd.Parameters.Add("@ProductID", SqlDbType.Int)
updateCmd.Parameters.Add("@VendorID", SqlDbType.Int)
Using vendorReader As SqlDataReader = vendorCmd.ExecuteReader()
While vendorReader.Read()
Console.WriteLine(vendorReader("Name"))
vendorID = CInt(vendorReader("VendorID"))
prodVendCmd.Parameters("@VendorID").Value = vendorID
prodVendReader = prodVendCmd.ExecuteReader()
Using prodVendReader
While (prodVendReader.Read)
productID = CInt(prodVendReader("ProductID"))
If IsDBNull(prodVendReader("OnOrderQty")) Then
minOrderQty = CInt(prodVendReader("MinOrderQty"))
onOrderQty = minOrderQty
Else
maxOrderQty = CInt(prodVendReader("MaxOrderQty"))
onOrderQty = CInt(maxOrderQty / 2)
End If
updateCmd.Parameters("@OrderQty").Value = onOrderQty
updateCmd.Parameters("@ProductID").Value = productID
updateCmd.Parameters("@VendorID").Value = vendorID
recordsUpdated = updateCmd.ExecuteNonQuery()
totalRecordsUpdated += recordsUpdated
End While
End Using
End While
End Using
Console.WriteLine("Total Records Updated: " & _
CStr(totalRecordsUpdated))
updateTx.Rollback()
Console.WriteLine("Transaction Rolled Back")
End Using
Console.WriteLine("Press any key to continue")
Console.ReadLine()
End Sub
Function GetConnectionString() As String
' To avoid storing the connection string in your code,
' you can retrieve it from a configuration file.
Return "..." & _
"MultipleActiveResultSets=True"
End Function
End Module
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
class Program
{
static void Main()
{
// By default, MARS is disabled when connecting
// to a MARS-enabled host.
// It must be enabled in the connection string.
string connectionString = GetConnectionString();
SqlTransaction updateTx = null;
SqlCommand vendorCmd = null;
SqlCommand prodVendCmd = null;
SqlCommand updateCmd = null;
SqlDataReader prodVendReader = null;
int vendorID = 0;
int productID = 0;
int minOrderQty = 0;
int maxOrderQty = 0;
int onOrderQty = 0;
int recordsUpdated = 0;
int totalRecordsUpdated = 0;
string vendorSQL =
"SELECT VendorID, Name FROM Purchasing.Vendor " +
"WHERE CreditRating = 5";
string prodVendSQL =
"SELECT ProductID, MaxOrderQty, MinOrderQty, OnOrderQty " +
"FROM Purchasing.ProductVendor " +
"WHERE VendorID = @VendorID";
string updateSQL =
"UPDATE Purchasing.ProductVendor " +
"SET OnOrderQty = @OrderQty " +
"WHERE ProductID = @ProductID AND VendorID = @VendorID";
using (SqlConnection awConnection =
new SqlConnection(connectionString))
{
awConnection.Open();
updateTx = awConnection.BeginTransaction();
vendorCmd = new SqlCommand(vendorSQL, awConnection);
vendorCmd.Transaction = updateTx;
prodVendCmd = new SqlCommand(prodVendSQL, awConnection);
prodVendCmd.Transaction = updateTx;
prodVendCmd.Parameters.Add("@VendorId", SqlDbType.Int);
updateCmd = new SqlCommand(updateSQL, awConnection);
updateCmd.Transaction = updateTx;
updateCmd.Parameters.Add("@OrderQty", SqlDbType.Int);
updateCmd.Parameters.Add("@ProductID", SqlDbType.Int);
updateCmd.Parameters.Add("@VendorID", SqlDbType.Int);
using (SqlDataReader vendorReader = vendorCmd.ExecuteReader())
{
while (vendorReader.Read())
{
Console.WriteLine(vendorReader["Name"]);
vendorID = (int) vendorReader["VendorID"];
prodVendCmd.Parameters["@VendorID"].Value = vendorID;
prodVendReader = prodVendCmd.ExecuteReader();
using (prodVendReader)
{
while (prodVendReader.Read())
{
productID = (int) prodVendReader["ProductID"];
if (prodVendReader["OnOrderQty"] == DBNull.Value)
{
minOrderQty = (int) prodVendReader["MinOrderQty"];
onOrderQty = minOrderQty;
}
else
{
maxOrderQty = (int) prodVendReader["MaxOrderQty"];
onOrderQty = (int)(maxOrderQty / 2);
}
updateCmd.Parameters["@OrderQty"].Value = onOrderQty;
updateCmd.Parameters["@ProductID"].Value = productID;
updateCmd.Parameters["@VendorID"].Value = vendorID;
recordsUpdated = updateCmd.ExecuteNonQuery();
totalRecordsUpdated += recordsUpdated;
}
}
}
}
Console.WriteLine("Total Records Updated: " +
totalRecordsUpdated.ToString());
updateTx.Rollback();
Console.WriteLine("Transaction Rolled Back");
}
Console.WriteLine("Press any key to continue");
Console.ReadLine();
}
private static string GetConnectionString()
{
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file.
return "..." +
"MultipleActiveResultSets=True";
}
}