Elaborazione di dati (MARS)
Prima dell'introduzione di MARS (Multiple Active Result Set), gli sviluppatori dovevano utilizzare più connessioni o cursori sul lato server per risolvere determinati scenari. Inoltre, quando venivano utilizzate più connessioni in una situazione di transazione, erano necessarie le connessioni associate (con sp_getbindtoken e sp_bindsession). Nei seguenti scenari viene illustrato come utilizzare una connessione con MARS abilitato anziché più connessioni.
Utilizzo di più comandi con MARS
Nella seguente applicazione console viene mostrato come utilizzare due oggetti SqlDataReader con due oggetti SqlCommand e un singolo oggetto SqlConnection con MARS abilitato.
Esempio
Nell'esempio viene aperta una singola connessione al database AdventureWorks. Utilizzando un oggetto SqlCommand viene creato un tipo SqlDataReader. Poiché viene utilizzato il lettore, viene aperto un secondo SqlDataReader, utilizzando i dati del primo SqlDataReader come input per la clausola WHERE per il secondo lettore.
Nota |
---|
Nell'esempio seguente viene utilizzato il database di esempio AdventureWorks incluso in SQL Server 2005.Per la stringa di connessione fornita nel codice di esempio si presuppone che il database sia installato e disponibile nel computer locale.Modificare la stringa di connessione per adattarla all'ambiente, se necessario. |
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 such as SQL Server 2005.
' 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 retrive it from a configuration file.
Return "Data Source=(local);Integrated Security=SSPI;" & _
"Initial Catalog=AdventureWorks; 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 such as SQL Server 2005.
// 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 retrive it from a configuration file.
return "Data Source=(local);Integrated Security=SSPI;" +
"Initial Catalog=AdventureWorks;MultipleActiveResultSets=True";
}
}
Lettura e aggiornamento dei dati con MARS
MARS consente di utilizzare una connessione per operazioni di lettura e operazioni DML (Data Manipulation Language) con più di un'operazione in sospeso. Questa funzionalità elimina la necessità, da parte di un'applicazione, di dover gestire errori dovuti a una connessione non disponibile. Inoltre, MARS è in grado di sostituire l'uso di cursori sul lato server, che di norma utilizzano più risorse. Infine, poiché su una singola connessione possono essere eseguite più operazioni, queste possono condividere lo stesso contesto di transazione, eliminando la necessità di utilizzare le stored procedure di sistema sp_getbindtoken e sp_bindsession.
Esempio
Nella seguente applicazione console viene mostrato come utilizzare due oggetti SqlDataReader con tre oggetti SqlCommand e un singolo oggetto SqlConnection con MARS abilitato. Il primo oggetto comando recupera un elenco di fornitori la cui posizione creditizia corrisponde a 5. Il secondo oggetto comando utilizza l'identificatore fornitore fornito da un oggetto SqlDataReader per caricare il secondo oggetto SqlDataReader con tutti i prodotti per il fornitore specifico. Il record di ciascun prodotto viene visitato dal secondo SqlDataReader. Viene calcolato il nuovo valore di OnOrderQty. Il terzo oggetto comando viene utilizzato per aggiornare la tabella ProductVendor con il nuovo valore. L'intero processo viene eseguito all'interno di una singola transazione, che viene quindi sottoposta a rollback.
Nota |
---|
Nell'esempio seguente viene utilizzato il database di esempio AdventureWorks incluso in SQL Server 2005.Per la stringa di connessione fornita nel codice di esempio si presuppone che il database sia installato e disponibile nel computer locale.Modificare la stringa di connessione per adattarla all'ambiente, se necessario. |
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 such as SQL Server 2005.
' 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 retrive it from a configuration file.
Return "Data Source=(local);Integrated Security=SSPI;" & _
"Initial Catalog=AdventureWorks;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 such as SQL Server 2005.
// 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 retrive it from a configuration file.
return "Data Source=(local);Integrated Security=SSPI;" +
"Initial Catalog=AdventureWorks;" +
"MultipleActiveResultSets=True";
}
}