Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
              Gäller för: .NET Framework 
 .NET .NET 
 Standard
I den här artikeln beskrivs stöd för asynkron programmering i Microsoft SqlClient Data Provider för SQL Server (SqlClient).
Äldre asynkron programmering
Microsoft SqlClient Data Provider för SQL Server innehåller metoder från System.Data.SqlClient för att upprätthålla bakåtkompatibilitet för program som migrerar till Microsoft.Data.SqlClient. Vi rekommenderar inte att du använder följande äldre asynkrona programmeringsmetoder för ny utveckling:
Tips/Råd
I Microsoft SqlClient Data Provider för SQL Server kräver Asynchronous Processing=true dessa äldre metoder inte längre i anslutningssträngen.
Varning
Anslutningsegenskapen Asynchronous Processing stöds inte längre i Microsoft SqlClient Data Provider v4.0 och senare.
Asynkrona programmeringsfunktioner
Dessa asynkrona programmeringsfunktioner ger en enkel teknik för att göra koden asynkron.
Mer information om asynkron programmering i .NET finns i:
När användargränssnittet inte svarar eller om servern inte skalas är det troligt att du behöver koden för att vara mer asynkron. Att skriva asynkron kod har traditionellt inneburet att installera ett återanrop (kallas även fortsättning) för att uttrycka logiken som inträffar när den asynkrona åtgärden har slutförts. Det här formatet komplicerar strukturen för asynkron kod jämfört med synkron kod.
Du kan anropa till asynkrona metoder utan att använda motringningar och utan att dela koden mellan flera metoder eller lambda-uttryck.
Modifieraren async anger att en metod är asynkron. När du anropar en async metod returneras en uppgift. När operatorn await tillämpas på en aktivitet avslutas den aktuella metoden omedelbart. När aktiviteten är klar återupptas körningen med samma metod.
Tips/Råd
I Microsoft SqlClient Data Provider för SQL Server krävs inte asynkrona anrop för att ange nyckelordet för anslutningssträngen Context Connection .
Att anropa en async metod skapar inte extra trådar. Den kan använda den befintliga I/O-slutförandetråden kort i slutet.
Följande metoder i Microsoft SqlClient Data Provider för SQL Server stöder asynkron programmering:
Andra asynkrona medlemmar har stöd för SqlClient-strömning.
Tips/Råd
Asynkrona metoder kräver Asynchronous Processing=true inte i anslutningssträngen. Och den här egenskapen är föråldrad i Microsoft SqlClient Data Provider för SQL Server.
Synkron till asynkron anslutning öppen
Du kan uppgradera ett befintligt program för att använda den asynkrona funktionen. Anta till exempel att ett program har en synkron anslutningsalgoritm och blockerar användargränssnittstråden varje gång det ansluter till databasen. När programmet är anslutet anropas en lagrad procedur som signalerar till andra användare av den som just loggade in.
using System;
using System.Data;
using Microsoft.Data.SqlClient;
namespace SqlCommandCS
{
    class Program
    {
        static void Main()
        {
            string str = "Data Source=(local);Initial Catalog=Northwind;"
                + "Integrated Security=SSPI";
            string qs = "SELECT OrderID, CustomerID FROM dbo.Orders;";
            CreateCommand(qs, str);
        }
        private static void CreateCommand(string queryString,
            string connectionString)
        {
            using (SqlConnection connection = new SqlConnection(
                       connectionString))
            {
                SqlCommand command = new SqlCommand(queryString, connection);
                command.Connection.Open();
                command.ExecuteNonQuery();
            }
        }
    }
}
När programmet konverteras för att använda asynkrona funktioner skulle det se ut så här:
using Microsoft.Data.SqlClient;
using System.Threading.Tasks;
class A {
   public static void Main() 
   {
      using (SqlConnection conn = new SqlConnection("Data Source=(local); Initial Catalog=NorthWind; Integrated Security=SSPI"))
      {
         SqlCommand command = new SqlCommand("SELECT TOP 2 * FROM dbo.Orders", conn);
         int result = A.Method(conn, command).Result;
         SqlDataReader reader = command.ExecuteReader();
         while (reader.Read())
            Console.WriteLine(reader[0]);
      }
   }
   static async Task<int> Method(SqlConnection conn, SqlCommand cmd) {
      await conn.OpenAsync();
      await cmd.ExecuteNonQueryAsync();
      return 1;
   }
}
Lägg till den asynkrona funktionen i ett befintligt program (blanda gamla och nya mönster)
Det går också att lägga till asynkron kapacitet (SqlConnection::OpenAsync) utan att ändra den befintliga asynkrona logiken. Om ett program till exempel för närvarande använder:
AsyncCallback productList = new AsyncCallback(ProductList);
SqlConnection conn = new SqlConnection("Data Source=(local); Initial Catalog=NorthWind; Integrated Security=SSPI");
conn.Open();
SqlCommand cmd = new SqlCommand("select top 2 * from orders", conn);
IAsyncResult ia = cmd.BeginExecuteReader(productList, cmd);
Du kan börja använda det asynkrona mönstret utan att väsentligen ändra den befintliga algoritmen.
using Microsoft.Data.SqlClient;
using System.Threading.Tasks;
class A 
{
   static void ProductList(IAsyncResult result) { }
   public static void Main() 
   {
      // AsyncCallback productList = new AsyncCallback(ProductList);
      // SqlConnection conn = new SqlConnection("Data Source=(local); Initial Catalog=NorthWind; Integrated Security=SSPI");
      // conn.Open();
      // SqlCommand cmd = new SqlCommand("select top 2 * from orders", conn);
      // IAsyncResult ia = cmd.BeginExecuteReader(productList, cmd);
      AsyncCallback productList = new AsyncCallback(ProductList);
      SqlConnection conn = new SqlConnection("Data Source=(local); Initial Catalog=NorthWind; Integrated Security=SSPI");
      conn.OpenAsync().ContinueWith((task) => {
         SqlCommand cmd = new SqlCommand("select top 2 * from orders", conn);
         IAsyncResult ia = cmd.BeginExecuteReader(productList, cmd);
      }, TaskContinuationOptions.OnlyOnRanToCompletion);
   }
}
Använd basprovidermodellen och den asynkrona funktionen
Du kan behöva skapa ett verktyg som kan ansluta till olika databaser och köra frågor. Du kan använda basprovidermodellen och den asynkrona funktionen.
Microsoft Distributed Transaction Controller (MSDTC) måste vara aktiverat på servern för att använda distribuerade transaktioner. Information om hur du aktiverar MSDTC finns i Aktivera MSDTC på en webbserver.
using System.Data.Common;
using Microsoft.Data.SqlClient;
using System.Threading.Tasks;
class program
{
   static async Task PerformDBOperationsUsingProviderModel(string connectionString)
   {
      using (DbConnection connection = SqlClientFactory.Instance.CreateConnection())
      {
            connection.ConnectionString = connectionString;
            await connection.OpenAsync();
            DbCommand command = connection.CreateCommand();
            command.CommandText = "SELECT * FROM AUTHORS";
            using (DbDataReader reader = await command.ExecuteReaderAsync())
            {
               while (await reader.ReadAsync())
               {
                  for (int i = 0; i < reader.FieldCount; i++)
                  {
                        // Process each column as appropriate
                        object obj = await reader.GetFieldValueAsync<object>(i);
                        Console.WriteLine(obj);
                  }
               }
            }
      }
   }
   public static void Main()
   {
      SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
      // replace these with your own values
      builder.DataSource = "localhost";
      builder.InitialCatalog = "pubs";
      builder.IntegratedSecurity = true;
      Task task = PerformDBOperationsUsingProviderModel(builder.ConnectionString);
      task.Wait();
   }
}
Använda SQL-transaktioner och den nya asynkrona funktionen
using Microsoft.Data.SqlClient;
using System.Threading.Tasks;
class Program 
{
   static void Main()
   {
      string connectionString =
          "Persist Security Info=False;Integrated Security=SSPI;database=Northwind;server=(local)";
      Task task = ExecuteSqlTransaction(connectionString);
      task.Wait();
   }
   static async Task ExecuteSqlTransaction(string connectionString)
   {
      using (SqlConnection connection = new SqlConnection(connectionString))
      {
         await connection.OpenAsync();
         SqlCommand command = connection.CreateCommand();
         SqlTransaction transaction = null;
         // Start a local transaction.
         transaction = await Task.Run<SqlTransaction>(
             () => connection.BeginTransaction("SampleTransaction")
             );
         // Must assign both transaction object and connection
         // to Command object for a pending local transaction
         command.Connection = connection;
         command.Transaction = transaction;
         try {
            command.CommandText =
                "Insert into Region (RegionID, RegionDescription) VALUES (555, 'Description')";
            await command.ExecuteNonQueryAsync();
            command.CommandText =
                "Insert into Region (RegionID, RegionDescription) VALUES (556, 'Description')";
            await command.ExecuteNonQueryAsync();
            // Attempt to commit the transaction.
            await Task.Run(() => transaction.Commit());
            Console.WriteLine("Both records are written to database.");
         }
         catch (Exception ex)
         {
            Console.WriteLine("Commit Exception Type: {0}", ex.GetType());
            Console.WriteLine("  Message: {0}", ex.Message);
            // Attempt to roll back the transaction.
            try
            {
               transaction.Rollback();
            }
            catch (Exception ex2)
            {
               // This catch block will handle any errors that may have occurred
               // on the server that would cause the rollback to fail, such as
               // a closed connection.
               Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType());
               Console.WriteLine("  Message: {0}", ex2.Message);
            }
         }
      }
   }
}
Använda distribuerade transaktioner och den nya asynkrona funktionen
I ett företagsprogram kan du behöva lägga till distribuerade transaktioner i vissa scenarier för att aktivera transaktioner mellan flera databasservrar. Du kan använda namnområdet System.Transactions och registrera en distribuerad transaktion enligt följande:
using Microsoft.Data.SqlClient;
using System.Threading.Tasks;
using System.Transactions;
class Program
{
   public static void Main()
   {
      SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
      // replace these with your own values
      // create two tables RegionTable1 and RegionTable2
      // and add a constraint in one of these tables 
      // to avoid duplicate RegionID
      builder.DataSource = "localhost";
      builder.InitialCatalog = "Northwind";
      builder.IntegratedSecurity = true;
      Task task = ExecuteDistributedTransaction(builder.ConnectionString, builder.ConnectionString);
      task.Wait();
   }
   static async Task ExecuteDistributedTransaction(string connectionString1, string connectionString2)
   {
      using (SqlConnection connection1 = new SqlConnection(connectionString1))
      using (SqlConnection connection2 = new SqlConnection(connectionString2))
      {
            using (CommittableTransaction transaction = new CommittableTransaction())
            {
               await connection1.OpenAsync();
               connection1.EnlistTransaction(transaction);
               await connection2.OpenAsync();
               connection2.EnlistTransaction(transaction);
               try
               {
                  SqlCommand command1 = connection1.CreateCommand();
                  command1.CommandText = "Insert into RegionTable1 (RegionID, RegionDescription) VALUES (100, 'Description')";
                  await command1.ExecuteNonQueryAsync();
                  SqlCommand command2 = connection2.CreateCommand();
                  command2.CommandText = "Insert into RegionTable2 (RegionID, RegionDescription) VALUES (100, 'Description')";
                  await command2.ExecuteNonQueryAsync();
                  transaction.Commit();
               }
               catch (Exception ex)
               {
                  Console.WriteLine("Exception Type: {0}", ex.GetType());
                  Console.WriteLine("  Message: {0}", ex.Message);
                  try
                  {
                        transaction.Rollback();
                  }
                  catch (Exception ex2)
                  {
                        Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType());
                        Console.WriteLine("  Message: {0}", ex2.Message);
                  }
               }
            }
      }
   }
}
Avbryt en asynkron åtgärd
Du kan avbryta en asynkron begäran med hjälp CancellationTokenav .
using Microsoft.Data.SqlClient;
using System.Threading;
using System.Threading.Tasks;
namespace Samples
{
   class CancellationSample
   {
      public static void Main(string[] args)
      {
            CancellationTokenSource source = new CancellationTokenSource();
            source.CancelAfter(2000); // give up after 2 seconds
            try
            {
               Task result = CancellingAsynchronousOperations(source.Token);
               result.Wait();
            }
            catch (AggregateException exception)
            {
               if (exception.InnerException is SqlException)
               {
                  Console.WriteLine("Operation canceled");
               }
               else
               {
                  throw;
               }
            }
      }
      static async Task CancellingAsynchronousOperations(CancellationToken cancellationToken)
      {
            using (SqlConnection connection = new SqlConnection("Server=(local);Integrated Security=true"))
            {
               await connection.OpenAsync(cancellationToken);
               SqlCommand command = new SqlCommand("WAITFOR DELAY '00:10:00'", connection);
               await command.ExecuteNonQueryAsync(cancellationToken);
            }
      }
   }
}
Asynkrona åtgärder med SqlBulkCopy
Asynkrona funktioner finns också i Microsoft.Data.SqlClient.SqlBulkCopy med SqlBulkCopy.WriteToServerAsync.
using System.Data;
using Microsoft.Data.SqlClient;
using System.Threading;
using System.Threading.Tasks;
namespace SqlBulkCopyAsyncCodeSample
{
    class Program
    {
        static string selectStatement = "SELECT * FROM [pubs].[dbo].[titles]";
        static string createDestTableStatement =
            @"CREATE TABLE {0} (
            [title_id] [varchar](6) NOT NULL,
            [title] [varchar](80) NOT NULL,
            [type] [char](12) NOT NULL,
            [pub_id] [char](4) NULL,
            [price] [money] NULL,
            [advance] [money] NULL,
            [royalty] [int] NULL,
            [ytd_sales] [int] NULL,
            [notes] [varchar](200) NULL,
            [pubdate] [datetime] NOT NULL)";
        // Replace the connection string if needed, for instance to connect to SQL Express: @"Server=(local)\SQLEXPRESS;Database=Demo;Integrated Security=true"
        // static string connectionString = @"Server=(localdb)\V11.0;Database=Demo";
        static string connectionString = @"Server=(local);Database=Demo;Integrated Security=true";
        // static string marsConnectionString = @"Server=(localdb)\V11.0;Database=Demo;MultipleActiveResultSets=true;";
        static string marsConnectionString = @"Server=(local);Database=Demo;MultipleActiveResultSets=true;Integrated Security=true";
        // Replace the Server name with your actual sql azure server name and User ID/Password
        static string azureConnectionString = @"Server=SqlAzure;User ID=<myUserID>;Password=<myPassword>;Database=Demo";
        static void Main(string[] args)
        {
            SynchronousSqlBulkCopy();
            AsyncSqlBulkCopy().Wait();
            MixSyncAsyncSqlBulkCopy().Wait();
            AsyncSqlBulkCopyNotifyAfter().Wait();
            AsyncSqlBulkCopyDataRows().Wait();
            AsyncSqlBulkCopySqlServerToSqlAzure().Wait();
            AsyncSqlBulkCopyCancel().Wait();
            AsyncSqlBulkCopyMARS().Wait();
        }
        // 3.1.1 Synchronous bulk copy in .NET 4.5
        private static void SynchronousSqlBulkCopy()
        {
            using (SqlConnection conn = new SqlConnection(connectionString))
            {
                conn.Open();
                DataTable dt = new DataTable();
                using (SqlCommand cmd = new SqlCommand(selectStatement, conn))
                {
                    SqlDataAdapter adapter = new SqlDataAdapter(cmd);
                    adapter.Fill(dt);
                    string temptable = "[#" + Guid.NewGuid().ToString("N") + "]";
                    cmd.CommandText = string.Format(createDestTableStatement, temptable);
                    cmd.ExecuteNonQuery();
                    using (SqlBulkCopy bcp = new SqlBulkCopy(conn))
                    {
                        bcp.DestinationTableName = temptable;
                        bcp.WriteToServer(dt);
                    }
                }
            }
        }
        // 3.1.2 Asynchronous bulk copy in .NET 4.5
        private static async Task AsyncSqlBulkCopy()
        {
            using (SqlConnection conn = new SqlConnection(connectionString))
            {
                await conn.OpenAsync();
                DataTable dt = new DataTable();
                using (SqlCommand cmd = new SqlCommand(selectStatement, conn))
                {
                    SqlDataAdapter adapter = new SqlDataAdapter(cmd);
                    adapter.Fill(dt);
                    string temptable = "[#" + Guid.NewGuid().ToString("N") + "]";
                    cmd.CommandText = string.Format(createDestTableStatement, temptable);
                    await cmd.ExecuteNonQueryAsync();
                    using (SqlBulkCopy bcp = new SqlBulkCopy(conn))
                    {
                        bcp.DestinationTableName = temptable;
                        await bcp.WriteToServerAsync(dt);
                    }
                }
            }
        }
        // 3.2 Add new Async.NET capabilities in an existing application (Mixing synchronous and asynchronous calls)
        private static async Task MixSyncAsyncSqlBulkCopy()
        {
            using (SqlConnection conn1 = new SqlConnection(connectionString))
            {
                conn1.Open();
                using (SqlCommand cmd = new SqlCommand(selectStatement, conn1))
                {
                    using (SqlDataReader reader = cmd.ExecuteReader())
                    {
                        using (SqlConnection conn2 = new SqlConnection(connectionString))
                        {
                            await conn2.OpenAsync();
                            string temptable = "[#" + Guid.NewGuid().ToString("N") + "]";
                            SqlCommand createCmd = new SqlCommand(string.Format(createDestTableStatement, temptable), conn2);
                            await createCmd.ExecuteNonQueryAsync();
                            using (SqlBulkCopy bcp = new SqlBulkCopy(conn2))
                            {
                                bcp.DestinationTableName = temptable;
                                await bcp.WriteToServerAsync(reader);
                            }
                        }
                    }
                }
            }
        }
        // 3.3 Using the NotifyAfter property
        private static async Task AsyncSqlBulkCopyNotifyAfter()
        {
            using (SqlConnection conn = new SqlConnection(connectionString))
            {
                await conn.OpenAsync();
                DataTable dt = new DataTable();
                using (SqlCommand cmd = new SqlCommand(selectStatement, conn))
                {
                    SqlDataAdapter adapter = new SqlDataAdapter(cmd);
                    adapter.Fill(dt);
                    string temptable = "[#" + Guid.NewGuid().ToString("N") + "]";
                    cmd.CommandText = string.Format(createDestTableStatement, temptable);
                    await cmd.ExecuteNonQueryAsync();
                    using (SqlBulkCopy bcp = new SqlBulkCopy(conn))
                    {
                        bcp.DestinationTableName = temptable;
                        bcp.NotifyAfter = 5;
                        bcp.SqlRowsCopied += new SqlRowsCopiedEventHandler(OnSqlRowsCopied);
                        await bcp.WriteToServerAsync(dt);
                    }
                }
            }
        }
        private static void OnSqlRowsCopied(object sender, SqlRowsCopiedEventArgs e)
        {
            Console.WriteLine("Copied {0} so far...", e.RowsCopied);
        }
        // 3.4 Using the new SqlBulkCopy Async.NET capabilities with DataRow[]
        private static async Task AsyncSqlBulkCopyDataRows()
        {
            using (SqlConnection conn = new SqlConnection(connectionString))
            {
                await conn.OpenAsync();
                DataTable dt = new DataTable();
                using (SqlCommand cmd = new SqlCommand(selectStatement, conn))
                {
                    SqlDataAdapter adapter = new SqlDataAdapter(cmd);
                    adapter.Fill(dt);
                    DataRow[] rows = dt.Select();
                    string temptable = "[#" + Guid.NewGuid().ToString("N") + "]";
                    cmd.CommandText = string.Format(createDestTableStatement, temptable);
                    await cmd.ExecuteNonQueryAsync();
                    using (SqlBulkCopy bcp = new SqlBulkCopy(conn))
                    {
                        bcp.DestinationTableName = temptable;
                        await bcp.WriteToServerAsync(rows);
                    }
                }
            }
        }
        // 3.5 Copying data from SQL Server to SQL Azure in .NET 4.5
        private static async Task AsyncSqlBulkCopySqlServerToSqlAzure()
        {
            using (SqlConnection srcConn = new SqlConnection(connectionString))
            using (SqlConnection destConn = new SqlConnection(azureConnectionString))
            {
                await srcConn.OpenAsync();
                await destConn.OpenAsync();
                using (SqlCommand srcCmd = new SqlCommand(selectStatement, srcConn))
                {
                    using (SqlDataReader reader = await srcCmd.ExecuteReaderAsync())
                    {
                        string temptable = "[#" + Guid.NewGuid().ToString("N") + "]";
                        using (SqlCommand destCmd = new SqlCommand(string.Format(createDestTableStatement, temptable), destConn))
                        {
                            await destCmd.ExecuteNonQueryAsync();
                            using (SqlBulkCopy bcp = new SqlBulkCopy(destConn))
                            {
                                bcp.DestinationTableName = temptable;
                                await bcp.WriteToServerAsync(reader);
                            }
                        }
                    }
                }
            }
        }
        // 3.6 Cancelling an Asynchronous Operation to SQL Azure
        private static async Task AsyncSqlBulkCopyCancel()
        {
            CancellationTokenSource cts = new CancellationTokenSource();
            using (SqlConnection srcConn = new SqlConnection(connectionString))
            using (SqlConnection destConn = new SqlConnection(azureConnectionString))
            {
                await srcConn.OpenAsync(cts.Token);
                await destConn.OpenAsync(cts.Token);
                using (SqlCommand srcCmd = new SqlCommand(selectStatement, srcConn))
                {
                    using (SqlDataReader reader = await srcCmd.ExecuteReaderAsync(cts.Token))
                    {
                        string temptable = "[#" + Guid.NewGuid().ToString("N") + "]";
                        using (SqlCommand destCmd = new SqlCommand(string.Format(createDestTableStatement, temptable), destConn))
                        {
                            await destCmd.ExecuteNonQueryAsync(cts.Token);
                            using (SqlBulkCopy bcp = new SqlBulkCopy(destConn))
                            {
                                bcp.DestinationTableName = temptable;
                                await bcp.WriteToServerAsync(reader, cts.Token);
                                //Cancel Async SqlBulCopy Operation after 200 ms
                                cts.CancelAfter(200);
                            }
                        }
                    }
                }
            }
        }
        // 3.7 Using Async.Net and MARS
        private static async Task AsyncSqlBulkCopyMARS()
        {
            using (SqlConnection marsConn = new SqlConnection(marsConnectionString))
            {
                await marsConn.OpenAsync();
                SqlCommand titlesCmd = new SqlCommand("SELECT * FROM [pubs].[dbo].[titles]", marsConn);
                SqlCommand authorsCmd = new SqlCommand("SELECT * FROM [pubs].[dbo].[authors]", marsConn);
                //With MARS we can have multiple active results sets on the same connection
                using (SqlDataReader titlesReader = await titlesCmd.ExecuteReaderAsync())
                using (SqlDataReader authorsReader = await authorsCmd.ExecuteReaderAsync())
                {
                    await authorsReader.ReadAsync();
                    string temptable = "[#" + Guid.NewGuid().ToString("N") + "]";
                    using (SqlConnection destConn = new SqlConnection(connectionString))
                    {
                        await destConn.OpenAsync();
                        using (SqlCommand destCmd = new SqlCommand(string.Format(createDestTableStatement, temptable), destConn))
                        {
                            await destCmd.ExecuteNonQueryAsync();
                            using (SqlBulkCopy bcp = new SqlBulkCopy(destConn))
                            {
                                bcp.DestinationTableName = temptable;
                                await bcp.WriteToServerAsync(titlesReader);
                            }
                        }
                    }
                }
            }
        }
    }
}
Asynkront använda flera kommandon med MARS
Exemplet öppnar en enda anslutning till AdventureWorks-databasen . Med hjälp av ett SqlCommand objekt skapas en SqlDataReader . När läsaren används öppnas en andra SqlDataReader , med data från den första SqlDataReader som indata till WHERE-satsen för den andra läsaren.
Anmärkning
I följande exempel används adventureworks-exempeldatabasen. Anslutningssträngen som anges i exempelkoden förutsätter att databasen är installerad och tillgänglig på den lokala datorn. Ändra anslutningssträngen efter behov för din miljö.
using System.Data.Common;
using Microsoft.Data.SqlClient;
using System.Threading.Tasks;
class Class1
{
    static void Main()
    {
        Task task = MultipleCommands();
        task.Wait();
    }
    static async Task MultipleCommands()
    {
        // By default, MARS is disabled when connecting to a MARS-enabled.
        // It must be enabled in the connection string.
        string connectionString = GetConnectionString();
        int vendorID;
        SqlDataReader productReader = null;
        string vendorSQL =
            "SELECT BusinessEntityID, 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.BusinessEntityID = @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);
            await awConnection.OpenAsync();
            using (SqlDataReader vendorReader = await vendorCmd.ExecuteReaderAsync())
            {
                while (await vendorReader.ReadAsync())
                {
                    Console.WriteLine(vendorReader["Name"]);
                    vendorID = (int)vendorReader["BusinessEntityID"];
                    productCmd.Parameters["@VendorId"].Value = vendorID;
                    // The following line of code requires a MARS-enabled connection.
                    productReader = await productCmd.ExecuteReaderAsync();
                    using (productReader)
                    {
                        while (await productReader.ReadAsync())
                        {
                            Console.WriteLine("  " +
                                productReader["Name"].ToString());
                        }
                    }
                }
            }
        }
    }
    private static string GetConnectionString()
    {
        // To avoid storing the connection string in your code, you can retrieve it from a configuration file.
        return "Data Source=(local);Integrated Security=SSPI;Initial Catalog=AdventureWorks;MultipleActiveResultSets=True";
    }
}
Asynkront läsa och uppdatera data med MARS
MARS tillåter att en anslutning används för både läsåtgärder och DML-åtgärder (datamanipuleringsspråk) med mer än en väntande åtgärd. Den här funktionen eliminerar behovet av att ett program hanterar anslutningsupptagna fel. MARS kan också ersätta användningen av markörer på serversidan, vilket i allmänhet förbrukar mer resurser. Eftersom flera åtgärder kan köras på en enda anslutning kan de slutligen dela samma transaktionskontext, vilket eliminerar behovet av att använda sp_getbindtoken och sp_bindsession system lagrade procedurer.
Följande konsolprogram visar hur du använder två SqlDataReader objekt med tre SqlCommand objekt och ett enda SqlConnection objekt med MARS aktiverat. Det första kommandoobjektet hämtar en lista över leverantörer vars kreditvärdighet är 5. Det andra kommandoobjektet använder det leverantörs-ID som tillhandahålls från en SqlDataReader för att läsa in det andra SqlDataReader med alla produkter för den specifika leverantören. Varje produktpost besöks av den andra SqlDataReader. En beräkning utförs för att avgöra vad den nya OnOrderQty ska vara. Det tredje kommandoobjektet används sedan för att uppdatera tabellen ProductVendor med det nya värdet. Hela den här processen sker inom en enda transaktion, som återställs i slutet.
Anmärkning
I följande exempel används adventureworks-exempeldatabasen. Anslutningssträngen som anges i exempelkoden förutsätter att databasen är installerad och tillgänglig på den lokala datorn. Ändra anslutningssträngen efter behov för din miljö.
using System.Data.Common;
using Microsoft.Data.SqlClient;
using System.Threading.Tasks;
class Program
{
    static void Main()
    {
        Task task = ReadingAndUpdatingData();
        task.Wait();
    }
    static async Task ReadingAndUpdatingData()
    {
        // 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 BusinessEntityID, Name FROM Purchasing.Vendor " +
            "WHERE CreditRating = 5";
        string prodVendSQL =
            "SELECT ProductID, MaxOrderQty, MinOrderQty, OnOrderQty " +
            "FROM Purchasing.ProductVendor " +
            "WHERE BusinessEntityID = @VendorID";
        string updateSQL =
            "UPDATE Purchasing.ProductVendor " +
            "SET OnOrderQty = @OrderQty " +
            "WHERE ProductID = @ProductID AND BusinessEntityID = @VendorID";
        using (SqlConnection awConnection =
            new SqlConnection(connectionString))
        {
            await awConnection.OpenAsync();
            updateTx = await Task.Run(() => 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 = await vendorCmd.ExecuteReaderAsync())
            {
                while (await vendorReader.ReadAsync())
                {
                    Console.WriteLine(vendorReader["Name"]);
                    vendorID = (int)vendorReader["BusinessEntityID"];
                    prodVendCmd.Parameters["@VendorID"].Value = vendorID;
                    prodVendReader = await prodVendCmd.ExecuteReaderAsync();
                    using (prodVendReader)
                    {
                        while (await prodVendReader.ReadAsync())
                        {
                            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 = await updateCmd.ExecuteNonQueryAsync();
                            totalRecordsUpdated += recordsUpdated;
                        }
                    }
                }
            }
            Console.WriteLine("Total Records Updated: ", totalRecordsUpdated.ToString());
            await Task.Run(() => updateTx.Rollback());
            Console.WriteLine("Transaction Rolled Back");
        }
    }
    private static string GetConnectionString()
    {
        // To avoid storing the connection string in your code, you can retrieve it from a configuration file.
        return "Data Source=(local);Integrated Security=SSPI;Initial Catalog=AdventureWorks;MultipleActiveResultSets=True";
    }
}