데이터 액세스 레이어의 연결 및 명령 수준 설정 구성(C#)

작성자 : Scott Mitchell

PDF 다운로드

형식화된 DataSet 내의 TableAdapters는 데이터베이스에 연결하고, 명령을 실행하고, DataTable을 결과로 채우는 작업을 자동으로 처리합니다. 그러나 이러한 세부 정보를 직접 처리하려는 경우가 있으며, 이 자습서에서는 TableAdapter에서 데이터베이스 연결 및 명령 수준 설정에 액세스하는 방법을 알아봅니다.

소개

자습서 시리즈 전체에서 Typed DataSets를 사용하여 계층화된 아키텍처의 데이터 액세스 계층 및 비즈니스 개체를 구현했습니다. 첫 번째 자습서에서 설명한 대로 Typed DataSet의 DataTable은 데이터의 리포지토리 역할을 하는 반면 TableAdapters는 기본 데이터를 검색하고 수정하기 위해 데이터베이스와 통신하는 래퍼 역할을 합니다. TableAdapters는 데이터베이스 작업과 관련된 복잡성을 캡슐화하고 데이터베이스에 연결하거나 명령을 실행하거나 결과를 DataTable에 채우는 코드를 작성할 필요가 없도록 합니다.

그러나 TableAdapter의 깊이로 잠복하고 ADO.NET 개체에서 직접 작동하는 코드를 작성해야 하는 경우가 있습니다. 예를 들어 트랜잭션 내 데이터베이스 수정 래핑 자습서에서는 트랜잭션을 시작, 커밋 및 롤백하기 위한 메서드를 TableAdapter에 추가 ADO.NET 했습니다. 이러한 메서드는 TableAdapter의 SqlCommand 개체에 할당된 수동으로 만든 SqlTransaction 내부 개체를 사용했습니다.

이 자습서에서는 TableAdapter에서 데이터베이스 연결 및 명령 수준 설정에 액세스하는 방법을 살펴보겠습니다. 특히 기본 연결 문자열 및 명령 시간 제한 설정에 액세스할 수 있도록 하는 기능을 ProductsTableAdapter 에 추가합니다.

ADO.NET 사용하여 데이터 작업

Microsoft .NET Framework 데이터 작업을 위해 특별히 설계된 다양한 클래스가 포함되어 있습니다. 네임스페이스 내에 있는 이러한 클래스를System.DataADO.NET 클래스라고 합니다. ADO.NET 우산 아래의 일부 클래스는 특정 데이터 공급자에 연결됩니다. 데이터 공급자를 ADO.NET 클래스와 기본 데이터 저장소 간에 정보를 전달할 수 있는 통신 채널로 생각할 수 있습니다. OleDb 및 ODBC와 같은 일반화된 공급자와 특정 데이터베이스 시스템을 위해 특별히 설계된 공급자가 있습니다. 예를 들어 OleDb 공급자를 사용하여 Microsoft SQL Server 데이터베이스에 연결할 수 있지만 SqlClient 공급자는 SQL Server 위해 특별히 설계되고 최적화되었기 때문에 훨씬 더 효율적입니다.

프로그래밍 방식으로 데이터에 액세스할 때 일반적으로 사용되는 패턴은 다음과 같습니다.

  • 데이터베이스에 대한 연결을 설정합니다.
  • 명령을 실행합니다.
  • 쿼리의 경우 SELECT 결과 레코드를 사용합니다.

이러한 각 단계를 수행하기 위한 별도의 ADO.NET 클래스가 있습니다. 예를 들어 SqlClient 공급자를 사용하여 데이터베이스에 연결하려면 클래스를 SqlConnection사용합니다. 데이터베이스에 INSERT, UPDATE, DELETE또는 SELECT 명령을 실행하려면 클래스를 SqlCommand사용합니다.

Transaction 자습서 내에서 데이터베이스 수정 래핑을 제외하고 TableAdapters 자동 생성 코드에는 데이터베이스에 연결하고, 명령을 실행하고, 데이터를 검색하고, 해당 데이터를 DataTable에 채우는 데 필요한 기능이 포함되어 있으므로 하위 수준 ADO.NET 코드를 직접 작성할 필요가 없습니다. 그러나 이러한 하위 수준 설정을 사용자 지정해야 하는 경우가 있을 수 있습니다. 다음 몇 단계를 통해 TableAdapters에서 내부적으로 사용되는 ADO.NET 개체를 활용하는 방법을 살펴봅히겠습니다.

1단계: 연결 속성을 사용하여 검사

각 TableAdapter 클래스에는 Connection 데이터베이스 연결 정보를 지정하는 속성이 있습니다. 이 속성의 데이터 형식 및 ConnectionString 값은 TableAdapter 구성 마법사에서 선택한 항목에 따라 결정됩니다. Typed DataSet에 TableAdapter를 처음 추가할 때 이 마법사는 데이터베이스 원본을 요청합니다(그림 1 참조). 이 첫 번째 단계의 드롭다운 목록에는 구성 파일에 지정된 데이터베이스와 Server Explorer 데이터 Connections 있는 다른 데이터베이스가 포함됩니다. 사용하려는 데이터베이스가 드롭다운 목록에 없는 경우 새 연결 단추를 클릭하고 필요한 연결 정보를 제공하여 새 데이터베이스 연결을 지정할 수 있습니다.

TableAdapter 구성 마법사의 첫 번째 단계

그림 1: TableAdapter 구성 마법사의 첫 번째 단계(전체 크기 이미지를 보려면 클릭)

잠시 시간을 내어 TableAdapter의 Connection 속성에 대한 코드를 검사해 보겠습니다. 데이터 액세스 계층 만들기 자습서에서 설명한 대로 클래스 뷰 창으로 이동하여 적절한 클래스로 드릴다운한 다음 멤버 이름을 두 번 클릭하여 자동으로 생성된 TableAdapter 코드를 볼 수 있습니다.

보기 메뉴로 이동하여 클래스 뷰를 선택하거나 Ctrl+Shift+C를 입력하여 클래스 뷰 창으로 이동합니다. 클래스 뷰 창의 위쪽 절반에서 네임스페이 NorthwindTableAdapters 스로 드릴다운하고 클래스를 ProductsTableAdapter 선택합니다. 그림 2와 같이 클래스 뷰의 아래쪽 절반에 멤버가 표시됩니다 ProductsTableAdapter . 속성을 두 번 클릭하여 Connection 해당 코드를 확인합니다.

클래스 뷰에서 연결 속성을 두 번 클릭하여 자동 생성된 코드를 봅니다.

그림 2: 클래스 뷰에서 연결 속성을 Double-Click 자동 생성된 코드를 봅니다.

TableAdapter의 Connection 속성 및 기타 연결 관련 코드는 다음과 같습니다.

private System.Data.SqlClient.SqlConnection _connection;
private void InitConnection() {
    this._connection = new System.Data.SqlClient.SqlConnection();
    this._connection.ConnectionString = 
        ConfigurationManager.ConnectionStrings["NORTHWNDConnectionString"].ConnectionString;
}
internal System.Data.SqlClient.SqlConnection Connection {
    get {
        if ((this._connection == null)) {
            this.InitConnection();
        }
        return this._connection;
    }
    set {
        this._connection = value;
        if ((this.Adapter.InsertCommand != null)) {
            this.Adapter.InsertCommand.Connection = value;
        }
        if ((this.Adapter.DeleteCommand != null)) {
            this.Adapter.DeleteCommand.Connection = value;
        }
        if ((this.Adapter.UpdateCommand != null)) {
            this.Adapter.UpdateCommand.Connection = value;
        }
        for (int i = 0; (i < this.CommandCollection.Length); i = (i + 1)) {
            if ((this.CommandCollection[i] != null)) {
                ((System.Data.SqlClient.SqlCommand)
                    (this.CommandCollection[i])).Connection = value;
            }
        }
    }
}

TableAdapter 클래스가 인스턴스화되면 멤버 변수 _connection 는 와 같습니다 null. 속성에 Connection 액세스하면 먼저 멤버 변수가 _connection 인스턴스화되었는지 확인합니다. 그렇지 않은 경우 메서드가 InitConnection 호출됩니다. 이 메서드는 해당 속성을 인스턴스화 _connection 하고 TableAdapter 구성 마법사의 첫 번째 단계에서 지정된 연결 문자열 값으로 설정합니다ConnectionString.

Connection 속성을 개체에 할당할 SqlConnection 수도 있습니다. 이렇게 하면 새 SqlConnection 개체를 각 TableAdapter 개체 SqlCommand 와 연결합니다.

2단계: Connection-Level 설정 노출

연결 정보는 TableAdapter 내에 캡슐화되어 있어야 하며 애플리케이션 아키텍처의 다른 계층에서 액세스할 수 없습니다. 그러나 쿼리, 사용자 또는 ASP.NET 페이지에 대해 TableAdapter의 연결 수준 정보에 액세스하거나 사용자 지정할 수 있어야 하는 시나리오가 있을 수 있습니다.

비즈니스 논리 계층에서 TableAdapter에서 Northwind 사용하는 연결 문자열 읽거나 변경하는 데 사용할 수 있는 속성을 포함 ConnectionString 하도록 DataSet의 를 확장 ProductsTableAdapter 해 보겠습니다.

참고

연결 문자열 사용할 공급자, 데이터베이스 위치, 인증 자격 증명 및 기타 데이터베이스 관련 설정과 같은 데이터베이스 연결 정보를 지정하는 문자열입니다. 다양한 데이터 저장소 및 공급자가 사용하는 연결 문자열 패턴 목록은 ConnectionStrings.com 참조하세요.

데이터 액세스 계층 만들기 자습서에서 설명한 대로 Partial 클래스를 사용하여 Typed DataSet의 자동 생성된 클래스를 확장할 수 있습니다. 먼저 폴더 아래에 라는 ConnectionAndCommandSettings 프로젝트에 새 하위 폴더를 ~/App_Code/DAL 만듭니다.

ConnectionAndCommandSettings라는 하위 폴더 추가

그림 3: 라는 하위 폴더 추가 ConnectionAndCommandSettings

라는 ProductsTableAdapter.ConnectionAndCommandSettings.cs 새 클래스 파일을 추가하고 다음 코드를 입력합니다.

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
namespace NorthwindTableAdapters
{
    public partial class ProductsTableAdapter
    {
        public string ConnectionString
        {
            get
            {
                return this.Connection.ConnectionString;
            }
            set
            {
                this.Connection.ConnectionString = value;
            }
        }
    }
}

이 partial 클래스는 public 모든 계층이 TableAdapter의 기본 연결에 대한 연결 문자열 읽거나 업데이트할 수 있도록 클래스에 라는 ConnectionStringProductsTableAdapter 속성을 추가합니다.

이 부분 클래스를 만들고 저장한 상태에서 클래스를 ProductsBLL 엽니다. 기존 메서드 중 하나로 이동하여 를 입력 Adapter 한 다음 마침표 키를 눌러 IntelliSense를 표시합니다. IntelliSense에서 사용할 수 있는 새 ConnectionString 속성이 표시되어야 합니다. 즉, BLL에서 이 값을 프로그래밍 방식으로 읽거나 조정할 수 있습니다.

전체 연결 개체 노출

이 partial 클래스는 기본 연결 개체의 속성 을 하나만 노출합니다 ConnectionString. TableAdapter의 범위를 벗어나 전체 연결 개체를 사용할 수 있도록 하려면 속성의 보호 수준을 변경할 Connection 수도 있습니다. 1단계에서 검사한 자동 생성된 코드는 TableAdapter의 속성이 로 internal표시되어 있음을 보여 줍니다. 즉, 동일한 어셈블리의 Connection 클래스에서만 액세스할 수 있습니다. 그러나 TableAdapter의 ConnectionModifier 속성을 통해 변경할 수 있습니다.

DataSet을 Northwind 열고 Designer 를 클릭한 ProductsTableAdapter 다음 속성 창 이동합니다. 기본값Assembly인 로 ConnectionModifier 설정된 가 표시됩니다. Typed DataSet 어셈블리 외부에서 속성을 사용할 수 있도록 Connection 하려면 속성을 Public로 변경 ConnectionModifier 합니다.

ConnectionModifier 속성을 통해 연결 속성의 접근성 수준을 구성할 수 있습니다.

그림 4: Connection 속성을 통해 ConnectionModifier 속성의 접근성 수준을 구성할 수 있습니다(전체 크기 이미지를 보려면 클릭).

DataSet을 저장한 다음 클래스로 ProductsBLL 돌아갑니다. 이전과 마찬가지로 기존 메서드 중 하나로 이동하여 를 입력 Adapter 한 다음 마침표 키를 눌러 IntelliSense를 표시합니다. 목록에는 속성이 Connection 포함되어야 합니다. 즉, 이제 BLL에서 프로그래밍 방식으로 연결 수준 설정을 읽거나 할당할 수 있습니다.

TableAdapter는 기본적으로 자동으로 생성된 INSERT, UPDATEDELETE 문이 있는 기본 쿼리로 구성됩니다. 이 기본 쿼리 , INSERTUPDATEDELETE 문은 TableAdapter 코드에서 속성을 통해 Adapter ADO.NET 데이터 어댑터 개체로 구현됩니다. 속성 Connection 과 마찬가지로 속성 Adapter 의 데이터 형식은 사용되는 데이터 공급자에 의해 결정됩니다. 이 자습서에서는 SqlClient 공급자를 사용하므로 속성은 Adapter 형식 SqlDataAdapter입니다.

TableAdapter의 Adapter 속성에는 , UPDATEDELETE 문을 발급INSERT하는 데 사용하는 형식 SqlCommand 의 세 가지 속성이 있습니다.

  • InsertCommand
  • UpdateCommand
  • DeleteCommand

SqlCommand 개체는 데이터베이스에 특정 쿼리를 전송하는 역할을 하며, 실행할 임시 SQL 문 또는 저장 프로시저를 포함하는 , 개체의 SqlParameter 컬렉션인 와 Parameters같은 CommandText속성을 가집니다. 데이터 액세스 계층 만들기 자습서에서 확인한 것처럼 이러한 명령 개체는 속성 창 통해 사용자 지정할 수 있습니다.

TableAdapter는 기본 쿼리 외에도 지정된 명령을 데이터베이스에 디스패치하는 다양한 메서드를 포함할 수 있습니다. 기본 쿼리의 명령 개체와 모든 추가 메서드에 대한 명령 개체는 TableAdapter의 CommandCollection 속성에 저장됩니다.

잠시 다음 두 속성과 해당 지원 멤버 변수 및 도우미 메서드에 대한 DataSet의 Northwind 에서 생성된 ProductsTableAdapter 코드를 살펴보겠습니다.

private System.Data.SqlClient.SqlDataAdapter _adapter;
private void InitAdapter() {
    this._adapter = new System.Data.SqlClient.SqlDataAdapter();
    
    ... Code that creates the InsertCommand, UpdateCommand, ...
    ... and DeleteCommand instances - omitted for brevity ...
}
private System.Data.SqlClient.SqlDataAdapter Adapter {
    get {
        if ((this._adapter == null)) {
            this.InitAdapter();
        }
        return this._adapter;
    }
}
private System.Data.SqlClient.SqlCommand[] _commandCollection;
private void InitCommandCollection() {
    this._commandCollection = new System.Data.SqlClient.SqlCommand[9];
    ... Code that creates the command objects for the main query and the ...
    ... ProductsTableAdapter�s other eight methods - omitted for brevity ...
}
protected System.Data.SqlClient.SqlCommand[] CommandCollection {
    get {
        if ((this._commandCollection == null)) {
            this.InitCommandCollection();
        }
        return this._commandCollection;
    }
}

CommandCollection 속성에 Adapter 대한 코드는 속성의 Connection 코드와 밀접하게 모방됩니다. 속성에서 사용하는 개체를 보유하는 멤버 변수가 있습니다. 속성 get 접근자가 해당 멤버 변수가 인지 확인하여 시작합니다 null. 이 경우 멤버 변수의 instance 만들고 핵심 명령 관련 속성을 할당하는 초기화 메서드가 호출됩니다.

4단계: Command-Level 설정 노출

이상적으로 명령 수준 정보는 데이터 액세스 계층 내에 캡슐화되어 있어야 합니다. 그러나 이 정보가 아키텍처의 다른 계층에서 필요한 경우 연결 수준 설정과 마찬가지로 부분 클래스를 통해 노출될 수 있습니다.

TableAdapter에는 단일 Connection 속성만 있으므로 연결 수준 설정을 노출하는 코드는 매우 간단합니다. TableAdapter에는 속성의 가변적인 수의 명령 개체와 함께 , UpdateCommand및 와 DeleteCommand같은 여러 명령 개체 InsertCommandCommandCollection 가 있을 수 있으므로 명령 수준 설정을 수정할 때 상황이 좀 더 복잡합니다. 명령 수준 설정을 업데이트할 때 이러한 설정은 모든 명령 개체로 전파되어야 합니다.

예를 들어 TableAdapter에 실행하는 데 매우 오랜 시간이 걸린 특정 쿼리가 있다고 상상해 보십시오. TableAdapter를 사용하여 이러한 쿼리 중 하나를 실행하는 경우 명령 개체의 CommandTimeout 속성을 늘릴 수 있습니다. 이 속성은 명령이 실행되기를 기다리는 시간(초)을 지정하고 기본값은 30입니다.

BLL에서 CommandTimeout 속성을 조정할 수 있도록 하려면 2단계()ProductsTableAdapter.ConnectionAndCommandSettings.cs에서 만든 partial 클래스 파일을 사용하여 에 다음 public 메서드 ProductsDataTable 를 추가합니다.

public void SetCommandTimeout(int timeout)
{
    if (this.Adapter.InsertCommand != null)
        this.Adapter.InsertCommand.CommandTimeout = timeout;
    if (this.Adapter.DeleteCommand != null)
        this.Adapter.DeleteCommand.CommandTimeout = timeout;
    if (this.Adapter.UpdateCommand != null)
        this.Adapter.UpdateCommand.CommandTimeout = timeout;
    for (int i = 0; i < this.CommandCollection.Length; i++)
        if (this.CommandCollection[i] != null)
            this.CommandCollection[i].CommandTimeout = timeout;
}

이 메서드는 BLL 또는 프레젠테이션 계층에서 호출하여 해당 TableAdapter instance 모든 명령 문제에 대한 명령 시간 제한을 설정할 수 있습니다.

참고

CommandCollection 속성은 Adapterprivate표시됩니다. 즉, TableAdapter 내의 코드에서만 액세스할 수 있습니다. 속성과 Connection 달리 이러한 액세스 한정자는 구성할 수 없습니다. 따라서 명령 수준 속성을 아키텍처의 다른 계층에 노출해야 하는 경우 위에서 설명한 부분 클래스 접근 방식을 사용하여 명령 개체를 읽거나 쓰는 private 메서드 또는 속성을 제공해야 public 합니다.

요약

형식화된 DataSet 내의 TableAdapters는 데이터 액세스 세부 정보 및 복잡성을 캡슐화하는 역할을 합니다. TableAdapters를 사용하면 데이터베이스에 연결하거나, 명령을 실행하거나, 결과를 DataTable로 채우기 위해 ADO.NET 코드를 작성하는 것에 대해 걱정할 필요가 없습니다. 그것은 모두 우리를 위해 자동으로 처리됩니다.

그러나 연결 문자열 또는 기본 연결 또는 명령 시간 제한 값 변경과 같은 하위 수준 ADO.NET 세부 사항을 사용자 지정해야 하는 경우가 있을 수 있습니다. TableAdapter에는 자동으로 생성된 Connection, AdapterCommandCollection 속성이 있지만 기본적으로 또는 private입니다internal. 이 내부 정보는 부분 클래스를 사용하여 TableAdapter를 확장하여 메서드 또는 속성을 포함 public 함으로써 노출될 수 있습니다. 또는 TableAdapter의 Connection 속성 액세스 한정자는 TableAdapter의 ConnectionModifier 속성을 통해 구성할 수 있습니다.

행복한 프로그래밍!

저자 정보

7개의 ASP/ASP.NET 책의 저자이자 4GuysFromRolla.com 창립자인 Scott Mitchell은 1998년부터 Microsoft 웹 기술로 작업해 왔습니다. Scott은 독립 컨설턴트, 트레이너 및 작가로 일합니다. 그의 최신 책은 샘스 티치 유어셀프 ASP.NET 24시간 만에 2.0입니다. 그는 에서mitchell@4GuysFromRolla.com 또는 에서 찾을 http://ScottOnWriting.NET수있는 자신의 블로그를 통해 도달 할 수 있습니다.

특별 감사

이 자습서 시리즈는 많은 유용한 검토자가 검토했습니다. 이 자습서의 수석 검토자는 버나데트 리, S 렌 제이콥 로리슨, 테레사 머피, 힐튼 가이세나우였습니다. 예정된 MSDN 문서를 검토하는 데 관심이 있으신가요? 그렇다면 에 줄을 놓습니다 mitchell@4GuysFromRolla.com.