하나의 열린 SqlConnection 연결을 통해 SqlBatch 객체의 순서화된 집합 SqlBatchCommand을 전송하는 데 사용합니다. 각 배치 명령어는 고유한 명령 텍스트, 명령 유형, 매개변수, 명령 동작, 그리고 영향을 받은 행 수 결과를 가집니다.
애플리케이션이 서로 다른 명령을 함께 보내고 싶을 때 사용합니다 SqlBatch . 작업이 하나의 문장이나 저장 프로시저일 때는 매개변수화된 SqlCommand 하나를 사용하세요. 큰 행 집합에는 SqlBulkCopy 또는 테이블 값 매개변수를 사용하세요.
이 글의 예시들은 connection라는 이름의 열려 있는 SqlConnection가 AdventureWorks 샘플 데이터베이스를 대상으로 한다고 가정합니다.
C# 예제는 using Microsoft.Data.SqlClient;를 요구합니다.
SqlDbType 또는 CommandBehavior를 사용하는 예시에는 using System.Data;도 필요합니다.
DbDataReader를 사용하는 예시에는 using System.Data.Common;이 필요합니다.
버전 및 플랫폼 지원
예제는 Microsoft.Data.SqlClient 7.1.0을 대상으로 합니다. 애플리케이션에 대해 Microsoft.Data.SqlClient support lifecycle에서 지원하는 패키지 버전과 대상 프레임워크를 선택하세요.
SqlBatch는 최신 .NET에서 DbBatch로부터 파생됩니다. Microsoft.Data.SqlClient는 또한 .NET 프레임워크 및 .NET Standard 2.0 패키지 자산에서도 SqlBatch를 노출합니다. 공개 API는 목표 프레임워크에 따라 다를 수 있으니, 각 대상마다 애플리케이션을 컴파일하세요.
배치 만들기
열린 연결에 대해 배치를 생성한 후, 실행 순서대로 명령을 추가합니다:
using var batch = new SqlBatch(connection);
batch.BatchCommands.Add(new SqlBatchCommand("""
SELECT TOP (3) ProductID, Name
FROM Production.Product
ORDER BY ProductID;
"""));
batch.BatchCommands.Add(new SqlBatchCommand("""
SELECT TOP (3) SalesOrderID, OrderDate
FROM Sales.SalesOrderHeader
ORDER BY SalesOrderID;
"""));
using DbDataReader reader = batch.ExecuteReader();
do
{
while (reader.Read())
{
Console.WriteLine($"{reader.GetValue(0)} | {reader.GetValue(1)}");
}
}
while (reader.NextResult());
CommandType.Text 기본값입니다. 저장 프로시저에 대해 배치 명령을 CommandType.StoredProcedure로 설정하세요.
CommandType.TableDirect을 설정하면 ArgumentOutOfRangeException 예외가 발생합니다.
배치 명령어에 매개변수 추가하기
매개변수는 SqlBatchCommand 개체에 속합니다. 두 배치 명령어에서 같은 플레이스홀더 이름이 값을 공유하지 않습니다:
using var batch = new SqlBatch(connection);
var products = new SqlBatchCommand("""
SELECT ProductID, Name
FROM Production.Product
WHERE ProductSubcategoryID = @id
ORDER BY ProductID;
""");
products.Parameters.Add("@id", SqlDbType.Int).Value = 2;
batch.BatchCommands.Add(products);
var orders = new SqlBatchCommand("""
SELECT SalesOrderID, OrderDate
FROM Sales.SalesOrderHeader
WHERE SalesPersonID = @id
ORDER BY SalesOrderID;
""");
orders.Parameters.Add("@id", SqlDbType.Int).Value = 279;
batch.BatchCommands.Add(orders);
using DbDataReader reader = batch.ExecuteReader();
각 매개변수의 SQL 타입과 데이터베이스 정의에서 적용 가능한 크기, 정밀도, 스케일을 설정하세요. 자세한 내용은 매개 변수 구성을 참조하십시오.
데이터를 변경하는 명령 실행
배치가 데이터를 변경하고 결과 행이 필요하지 않을 때 ExecuteNonQuery 또는 ExecuteNonQueryAsync을 사용하세요. 반환된 값은 행 수를 사용할 수 있는 경우 영향을 받은 총 행 수입니다. 실행 후에는 각 명령어가 RecordsAffected 자체 카운트를 보고합니다.
다음 예시는 변경 사항을 되돌립니다:
using SqlTransaction transaction = connection.BeginTransaction();
using var batch = new SqlBatch(connection, transaction);
var firstUpdate = new SqlBatchCommand("""
UPDATE Sales.SalesOrderHeader
SET Status = @status
WHERE SalesOrderID = @salesOrderId;
""");
firstUpdate.Parameters.Add("@status", SqlDbType.TinyInt).Value = 2;
firstUpdate.Parameters.Add("@salesOrderId", SqlDbType.Int).Value = 43659;
batch.BatchCommands.Add(firstUpdate);
var secondUpdate = new SqlBatchCommand("""
UPDATE Sales.SalesOrderHeader
SET Status = @status
WHERE SalesOrderID = @salesOrderId;
""");
secondUpdate.Parameters.Add("@status", SqlDbType.TinyInt).Value = 2;
secondUpdate.Parameters.Add("@salesOrderId", SqlDbType.Int).Value = 43660;
batch.BatchCommands.Add(secondUpdate);
int totalRows = batch.ExecuteNonQuery();
Console.WriteLine($"Total rows: {totalRows}");
foreach (SqlBatchCommand command in batch.BatchCommands)
{
Console.WriteLine(command.RecordsAffected);
}
transaction.Rollback();
여러 결과 보기
명령이 행을 반환하면 ExecuteReader 또는 ExecuteReaderAsync을 사용하세요. 리더는 배치 명령 순서로 결과를 노출합니다.
NextResultAsync이(가) 반환될 때까지 false 또는 NextResult을(를) 호출하세요.
명령어는 행 집합이 없거나, 한 행 집합을 생성하거나, 여러 행 집합을 생성할 수 있습니다. 한 NextResult 통화가 하나의 SqlBatchCommand로 연결된다고 가정하지 마세요.
명령 동작 사용하기
리더가 순차적 액세스가 필요하거나 연결을 종료해야 할 때 배치 수준 CommandBehavior를 ExecuteReader 또는 ExecuteReaderAsync에 전달합니다:
using var batch = new SqlBatch(connection);
batch.BatchCommands.Add(new SqlBatchCommand("""
SELECT DocumentSummary
FROM Production.Document
WHERE DocumentSummary IS NOT NULL;
"""));
using DbDataReader reader =
batch.ExecuteReader(CommandBehavior.SequentialAccess);
char[] buffer = new char[4096];
while (reader.Read())
{
using TextReader summary = reader.GetTextReader(0);
int count;
while ((count = summary.Read(buffer, 0, buffer.Length)) > 0)
{
Console.Out.Write(buffer, 0, count);
}
Console.WriteLine();
}
배치 레벨 오버로드는 CommandBehavior.SequentialAccess, CommandBehavior.CloseConnection, CommandBehavior.Default 및 그 값들의 조합만 받습니다.
SingleRow, SchemaOnly, KeyInfo와 같은 다른 유효한 값은 배치 수준 오버로드에 전달되면 ArgumentOutOfRangeException 예외를 발생시킵니다. 배치 수준의 동작 오버로드는 Microsoft.Data.SqlClient 7.1부터 사용할 수 있습니다.
SchemaOnly을(를) 개별 명령에 설정하여 KeyInfo, SingleRow, CommandBehavior와 같은 옵션에 적용합니다.
CloseConnection 및 SequentialAccess에 배치 수준 오버로드를 사용합니다.
트랜잭션을 사용하세요
SqlBatch 명령을 원자적으로 만들지 않습니다. 모든 명령어가 커밋되거나 롤백되어야 할 때 명시적 트랜잭션을 사용하세요. 이 예시는 AdventureWorks가 변하지 않도록 되돌립니다:
using SqlTransaction transaction = connection.BeginTransaction();
using var batch = new SqlBatch(connection, transaction);
batch.BatchCommands.Add(new SqlBatchCommand("""
UPDATE Sales.SalesOrderHeader
SET Status = 2
WHERE SalesOrderID = 43659;
"""));
batch.BatchCommands.Add(new SqlBatchCommand("""
UPDATE Sales.SalesOrderHeader
SET Status = 2
WHERE SalesOrderID = 43660;
"""));
batch.ExecuteNonQuery();
transaction.Rollback();
애플리케이션이 전체 배치를 수락할 때만 Rollback 대신 Commit를 호출하세요. 실행 전에 트랜잭션을 할당하세요. 트랜잭션과 배치는 반드시 동일한 연결을 사용해야 합니다. SqlClient는 비동기 트랜잭션 메서드 BeginTransactionAsync, CommitAsync, RollbackAsync를 덮어쓰지 않으므로 동기적으로 완료됩니다. 자세한 내용은 작업 기반 SQL 트랜잭션 메서드 사용을 참조하세요.
타임아웃, 취소, 오류 처리
배치의 시간을 초 단위로 Timeout 설정합니다. 배치는 해당 연결을 구성한 경우 Command Timeout 설정을 사용합니다. 그렇지 않으면 기본값은 30초입니다. 값 0에는 시간 제한이 없으며, 음수 값은 ArgumentException을 발생시킵니다. 호출자가 대기하는 것을 멈춰야 할 때 취소 토큰을 비동기 실행 메서드에 전달하거나 Cancel를 호출합니다. 취소는 보장되지 않을 수 있습니다. 작업이 취소가 적용되기 전에 완료될 수도 있습니다.
실행이 실패하면 Errors을 catch하고 그 SqlException 컬렉션의 모든 항목을 검사합니다.
BatchCommand은 해당 정보를 사용할 수 있을 때 연결된 SqlBatchCommand을 식별합니다:
using var batch = new SqlBatch(connection);
batch.BatchCommands.Add(new SqlBatchCommand(
"SELECT TOP (1) ProductID FROM Production.Product;"));
batch.BatchCommands.Add(new SqlBatchCommand("SELECT 1 / 0;"));
try
{
using DbDataReader reader = batch.ExecuteReader();
do
{
while (reader.Read())
{
Console.WriteLine(reader.GetValue(0));
}
}
while (reader.NextResult());
}
catch (SqlException exception)
{
Console.WriteLine(
exception.BatchCommand is null
? "The batch failed."
: $"Failed command: {exception.BatchCommand.CommandText}");
}
리더 실행은 점진적입니다. 나중 배치 명령의 오류는 Read 또는 NextResult이 해당 명령으로 진행될 때 표면화될 수 있으므로, try 블록 내에서 리더를 처리하세요.
자격 증명, 토큰, 민감한 데이터가 포함된 매개변수 값을 기록하지 마세요. 오류 필드와 정보 메시지에 대해서는 오류 및 메시지 처리를 참조하세요.