Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Şunlar için geçerlidir: .NET Framework
.NET
.NET Standard
Bu makalede SQL Server için Microsoft SqlClient Veri Sağlayıcısı'nda (SqlClient) zaman uyumsuz programlama desteği ele alınmaktadır.
Eski zaman uyumsuz programlama
SQL Server için Microsoft SqlClient Veri Sağlayıcısı, uygulamasına geçiş yapılan uygulamaların geriye dönük uyumluluğunu korumak için Microsoft.Data.SqlClient yöntemler içerir. Yeni geliştirme için aşağıdaki eski zaman uyumsuz programlama yöntemlerinin kullanılması önerilmez:
Tip
SQL Server için Microsoft SqlClient Veri Sağlayıcısı'nda, bu eski yöntemler artık bağlantı dizesinde gerekli Asynchronous Processing=true değildir.
Uyarı
Asynchronous Processing Bağlantı özelliği artık Microsoft SqlClient Veri Sağlayıcısı v4.0'da desteklenmemektedir.
Zaman uyumsuz programlama özellikleri
Bu zaman uyumsuz programlama özellikleri, kodu zaman uyumsuz hale getirmek için basit bir teknik sağlar.
.NET'te zaman uyumsuz programlama hakkında daha fazla bilgi için bkz:
Kullanıcı arabiriminiz yanıt vermiyorsa veya sunucunuz ölçeklendirilmiyorsa kodunuzun daha zaman uyumsuz olması gerekebilir. Zaman uyumsuz kod yazmak, zaman uyumsuz işlem tamamlandıktan sonra oluşan mantığı ifade etmek için geleneksel olarak bir geri çağırma (devamlılık olarak da adlandırılır) yüklemeyi içerir. Bu stil, zaman uyumlu kodla karşılaştırıldığında zaman uyumsuz kodun yapısını karmaşıklaştırır.
Geri çağırmaları kullanmadan ve kodunuzu birden çok yönteme veya lambda ifadesine bölmeden zaman uyumsuz yöntemlere çağrı yapabilirsiniz.
Değiştirici, async bir yöntemin zaman uyumsuz olduğunu belirtir. Bir async yöntem çağrılırken bir görev döndürülür. İşleç await bir göreve uygulandığında geçerli yöntem hemen çıkar. Görev tamamlandığında, yürütme aynı yöntemde devam eder.
Tip
SQL Server için Microsoft SqlClient Veri Sağlayıcısı'nda, bağlantı dizesi anahtar sözcüğünü Context Connection ayarlamak için zaman uyumsuz çağrılar gerekli değildir.
Bir async yöntemi çağırmak fazladan iş parçacığı oluşturmaz. Sonunda mevcut G/Ç tamamlama iş parçacığını kısa bir süre kullanabilir.
SQL Server için Microsoft SqlClient Veri Sağlayıcısı'ndaki aşağıdaki yöntemler zaman uyumsuz programlamayı destekler:
Diğer zaman uyumsuz üyeler SqlClient akış desteğini destekler.
Tip
Zaman uyumsuz yöntemler, bağlantı dizesinde gerekli Asynchronous Processing=true değildir. Ve bu özellik SQL Server için Microsoft SqlClient Veri Sağlayıcısı'nda kullanımdan kaldırıldı.
Zaman uyumsuz bağlantıyla zaman uyumlu açık
Mevcut bir uygulamayı zaman uyumsuz özelliği kullanacak şekilde yükseltebilirsiniz. Örneğin, bir uygulamanın zaman uyumlu bir bağlantı algoritması olduğunu ve veritabanına her bağlandığında UI iş parçacığını engellediğini varsayalım. Bağlandıktan sonra uygulama, yeni oturum açan diğer kullanıcılara işaret eden bir saklı yordam çağırır.
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();
}
}
}
}
Zaman uyumsuz işlevselliği kullanmak üzere dönüştürüldüğünde, program şöyle görünü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;
}
}
Mevcut bir uygulamaya zaman uyumsuz özelliği ekleme (eski ve yeni desenleri karıştırma)
Mevcut zaman uyumsuz mantığı değiştirmeden zaman uyumsuz yetenek (SqlConnection::OpenAsync) eklemek de mümkündür. Örneğin, bir uygulama şu anda kullanıyorsa:
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);
Mevcut algoritmayı önemli ölçüde değiştirmeden zaman uyumsuz deseni kullanmaya başlayabilirsiniz.
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);
}
}
Temel sağlayıcı modelini ve zaman uyumsuz özelliği kullanma
Farklı veritabanlarına bağlanabilen ve sorgu yürütebilen bir araç oluşturmanız gerekebilir. Temel sağlayıcı modelini ve zaman uyumsuz özelliği kullanabilirsiniz.
Dağıtılmış işlemleri kullanmak için sunucuda Microsoft Dağıtılmış İşlem Denetleyicisi'nin (MSDTC) etkinleştirilmesi gerekir. MSDTC'yi etkinleştirme hakkında bilgi için bkz. Web Sunucusunda MSDTC'yi Etkinleştirme.
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();
}
}
SQL işlemlerini ve yeni zaman uyumsuz özelliği kullanma
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);
}
}
}
}
}
Dağıtılmış işlemleri ve yeni zaman uyumsuz özelliği kullanma
Kurumsal bir uygulamada, birden çok veritabanı sunucusu arasında işlemleri etkinleştirmek için bazı senaryolara dağıtılmış işlemler eklemeniz gerekebilir. System.Transactions ad alanını kullanabilir ve dağıtılmış bir işlemi aşağıdaki gibi kaydedebilirsiniz:
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);
}
}
}
}
}
}
Zaman uyumsuz işlemi iptal etme
kullanarak zaman uyumsuz bir isteği CancellationTokeniptal edebilirsiniz.
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);
}
}
}
}
SqlBulkCopy ile zaman uyumsuz işlemler
Zaman uyumsuz özellikler ile de içindedir Microsoft.Data.SqlClient.SqlBulkCopySqlBulkCopy.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);
}
}
}
}
}
}
}
}
MARS ile birden çok komutu zaman uyumsuz olarak kullanma
Örnek , AdventureWorks veritabanına tek bir bağlantı açar. Bir SqlCommand nesne kullanılarak bir SqlDataReader oluşturulur. Okuyucu kullanıldıkçe, ikinci SqlDataReader okuyucunun WHERE yan tümcesine giriş olarak ilkinden SqlDataReader veriler kullanılarak bir saniye açılır.
Uyarı
Aşağıdaki örnekte örnek AdventureWorks veritabanı kullanılmaktadır. Örnek kodda sağlanan bağlantı dizesi, veritabanının yüklü olduğunu ve yerel bilgisayarda kullanılabilir olduğunu varsayar. Bağlantı dizesini ortamınız için gerektiği gibi değiştirin.
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";
}
}
MARS ile verileri zaman uyumsuz olarak okuma ve güncelleştirme
MARS, birden fazla bekleyen işlemle hem okuma işlemleri hem de veri işleme dili (DML) işlemleri için bir bağlantının kullanılmasına olanak tanır. Bu özellik, bir uygulamanın bağlantı meşgul hatalarıyla başa çıkma gereksinimini ortadan kaldırır. Ayrıca MARS, genellikle daha fazla kaynak tüketen sunucu tarafı imleçlerin kullanımını değiştirebilir. Son olarak, birden çok işlem tek bir bağlantı üzerinde çalışabildiğinden aynı işlem bağlamını paylaşabilir ve bu da sp_getbindtoken ve sp_bindsession sistem saklı yordamlarını kullanma gereksinimini ortadan kaldırır.
Aşağıdaki Konsol uygulaması, üç SqlDataReader nesneyle iki SqlCommand nesnenin ve MARS'ın etkinleştirildiği tek SqlConnection bir nesnenin nasıl kullanılacağını gösterir. İlk komut nesnesi, kredi derecelendirmesi 5 olan satıcıların listesini alır. İkinci komut nesnesi, ikincisini belirli bir satıcının tüm ürünleriyle yüklemek SqlDataReader için öğesinden SqlDataReader sağlanan satıcı kimliğini kullanır. Her ürün kaydı ikinci SqlDataReadertarafından ziyaret edilir. Yeni OnOrderQty'nin ne olması gerektiğini belirlemek için bir hesaplama gerçekleştirilir. Üçüncü komut nesnesi daha sonra ProductVendor tablosunu yeni değerle güncelleştirmek için kullanılır. Bu işlemin tamamı, sonunda geri alınan tek bir işlem içinde gerçekleşir.
Uyarı
Aşağıdaki örnekte örnek AdventureWorks veritabanı kullanılmaktadır. Örnek kodda sağlanan bağlantı dizesi, veritabanının yüklü olduğunu ve yerel bilgisayarda kullanılabilir olduğunu varsayar. Bağlantı dizesini ortamınız için gerektiği gibi değiştirin.
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";
}
}