데이터 소스 제어

작성자: Microsoft

ASP.NET 1.x의 DataGrid 컨트롤은 웹 애플리케이션의 데이터 액세스가 크게 향상되었습니다. 그러나 사용자 친화적인 것은 아니었습니다. 많은 유용한 기능을 얻으려면 여전히 상당한 양의 코드가 필요했습니다. 1.x의 모든 데이터 액세스 노력의 모델입니다.

ASP.NET 1.x의 DataGrid 컨트롤은 웹 애플리케이션의 데이터 액세스가 크게 향상되었습니다. 그러나 사용자 친화적인 것은 아니었습니다. 많은 유용한 기능을 얻으려면 여전히 상당한 양의 코드가 필요했습니다. 1.x의 모든 데이터 액세스 노력의 모델입니다.

ASP.NET 2.0은 데이터 원본 제어를 사용하여 이 문제를 부분적으로 해결합니다. ASP.NET 2.0의 데이터 원본 컨트롤은 개발자에게 데이터 검색, 데이터 표시 및 데이터 편집을 위한 선언적 모델을 제공합니다. 데이터 원본 제어의 목적은 해당 데이터의 원본에 관계없이 데이터 바인딩된 컨트롤에 일관된 데이터 표현을 제공하는 것입니다. ASP.NET 2.0의 데이터 원본 컨트롤의 핵심은 DataSourceControl 추상 클래스입니다. DataSourceControl 클래스는 IDataSource 인터페이스 및 IListSource 인터페이스의 기본 구현을 제공하며, 그 중 후자는 데이터 원본 제어를 데이터 바인딩된 컨트롤의 DataSource로 할당하고(나중에 설명한 새 DataSourceId 속성을 통해) 그 안에 있는 데이터를 목록으로 노출할 수 있습니다. 데이터 원본 컨트롤의 각 데이터 목록은 DataSourceView 개체로 노출됩니다. DataSourceView 인스턴스에 대한 액세스는 IDataSource 인터페이스에서 제공됩니다. 예를 들어 GetViewNames 메서드는 특정 데이터 원본 컨트롤과 연결된 DataSourceViews를 열거할 수 있는 ICollection을 반환하고 GetView 메서드를 사용하면 이름으로 특정 DataSourceView instance 액세스할 수 있습니다.

데이터 원본 컨트롤에는 사용자 인터페이스가 없습니다. 선언적 구문을 지원할 수 있고 원하는 경우 페이지 상태에 액세스할 수 있도록 서버 컨트롤로 구현됩니다. 데이터 원본 컨트롤은 HTML 태그를 클라이언트에 렌더링하지 않습니다.

참고

나중에 볼 수 있듯이 데이터 원본 제어를 사용하여 얻을 수 있는 캐싱 혜택도 있습니다.

연결 문자열 저장

데이터 원본 제어를 구성하는 방법을 살펴보기 전에 연결 문자열과 관련된 ASP.NET 2.0의 새로운 기능을 다루어야 합니다. ASP.NET 2.0에는 런타임에 동적으로 읽을 수 있는 연결 문자열을 쉽게 저장할 수 있는 새 섹션이 구성 파일에 도입되었습니다. <connectionStrings 섹션을> 사용하면 연결 문자열을 쉽게 저장할 수 있습니다.

아래 코드 조각은 새 연결 문자열을 추가합니다.

<connectionStrings> <add name="Northwind" connectionString="Data Source=localhost; Integrated Security=SSPI;Initial Catalog=Northwind;" providerName="System.Data.SqlClient" /> </connectionStrings>

참고

appSettings 섹션과 <마찬가지로 connectionStrings> 섹션은 구성 파일의 <system.web> 섹션 외부에 <표시됩니다.>

이 연결 문자열을 사용하려면 서버 컨트롤의 ConnectionString 특성을 설정할 때 다음 구문을 사용할 수 있습니다.

ConnectionString="<%$ ConnectionStrings:Northwind%>"

<중요한 정보가 노출되지 않도록 connectionStrings> 섹션을 암호화할 수도 있습니다. 해당 기능은 이후 모듈에서 다룹니다.

데이터 원본 캐싱

각 DataSourceControl은 캐싱을 구성하기 위한 네 가지 속성을 제공합니다. EnableCaching, CacheDuration, CacheExpirationPolicy 및 CacheKeyDependency.

EnableCaching

EnableCaching은 데이터 소스 제어에 대해 캐싱을 사용할 수 있는지 여부를 결정하는 부울 속성입니다.

CacheDuration 속성

CacheDuration 속성은 캐시가 유효한 상태로 유지되는 시간(초)을 설정합니다. 이 속성을 0 으로 설정하면 캐시가 명시적으로 무효화될 때까지 유효한 상태로 유지됩니다.

CacheExpirationPolicy 속성

CacheExpirationPolicy 속성을 Absolute 또는 Sliding로 설정할 수 있습니다. 절대값으로 설정하면 데이터가 캐시되는 최대 시간은 CacheDuration 속성에 지정된 시간(초)입니다. 슬라이딩으로 설정하면 각 작업이 수행될 때 만료 시간이 다시 설정됩니다.

CacheKeyDependency 속성

CacheKeyDependency 속성에 문자열 값을 지정하면 ASP.NET 해당 문자열을 기반으로 새 캐시 종속성을 설정합니다. 이렇게 하면 CacheKeyDependency를 변경하거나 제거하여 캐시를 명시적으로 무효화할 수 있습니다.

중요: 가장을 사용하도록 설정하고 데이터 원본 및/또는 데이터 콘텐츠에 대한 액세스가 클라이언트 ID를 기반으로 하는 경우 EnableCaching을 False로 설정하여 캐싱을 사용하지 않도록 설정하는 것이 좋습니다. 이 시나리오에서 캐싱을 사용하도록 설정하고 원래 데이터를 요청한 사용자 이외의 사용자가 요청을 발급하는 경우 데이터 원본에 대한 권한 부여가 적용되지 않습니다. 데이터는 단순히 캐시에서 제공됩니다.

SqlDataSource 컨트롤

SqlDataSource 컨트롤을 사용하면 개발자가 ADO.NET 지원하는 관계형 데이터베이스에 저장된 데이터에 액세스할 수 있습니다. System.Data.SqlClient 공급자를 사용하여 SQL Server 데이터베이스, System.Data.OleDb 공급자, System.Data.Odbc 공급자 또는 System.Data.OracleClient 공급자에 액세스하여 Oracle에 액세스할 수 있습니다. 따라서 SqlDataSource는 SQL Server 데이터베이스의 데이터에 액세스하는 데만 사용되는 것이 아닙니다.

SqlDataSource를 사용하려면 ConnectionString 속성에 대한 값을 제공하고 SQL 명령 또는 저장 프로시저를 지정하기만 하면 됩니다. SqlDataSource 컨트롤은 기본 ADO.NET 아키텍처 작업을 처리합니다. 연결을 열고, 데이터 원본을 쿼리하거나, 저장 프로시저를 실행하고, 데이터를 반환한 다음, 연결을 닫습니다.

참고

DataSourceControl 클래스는 자동으로 연결을 닫기 때문에 데이터베이스 연결 누수하여 생성된 고객 호출 수를 줄여야 합니다.

아래 코드 조각은 위와 같이 구성 파일에 저장된 연결 문자열을 사용하여 DropDownList 컨트롤을 SqlDataSource 컨트롤에 바인딩합니다.

<asp:SqlDataSource id="SqlDataSource1" runat="server" DataSourceMode="DataReader" ConnectionString="<%$ ConnectionStrings:Northwind%>" SelectCommand="SELECT EmployeeID, LastName FROM Employees"> </asp:SqlDataSource><asp:DropDownList id="ListBox1" runat="server" DataTextField="LastName" DataValueField="EmployeeID" DataSourceID="SqlDataSource1"> </asp:DropDownList>

위에서 설명한 것처럼 SqlDataSource의 DataSourceMode 속성은 데이터 원본에 대한 모드를 지정합니다. 위의 예제에서 DataSourceMode는 DataReader로 설정됩니다. 이 경우 SqlDataSource는 정방향 전용 및 읽기 전용 커서를 사용하여 IDataReader 개체를 반환합니다. 반환되는 지정된 형식의 개체는 사용되는 공급자에 의해 제어됩니다. 이 경우 web.config 파일의 connectionStrings> 섹션에 <지정된 대로 System.Data.SqlClient 공급자를 사용합니다. 따라서 반환되는 개체는 SqlDataReader 형식입니다. DataSet의 DataSourceMode 값을 지정하여 데이터를 서버의 DataSet에 저장할 수 있습니다. 이 모드를 사용하면 정렬, 페이징 등의 기능을 추가할 수 있습니다. SqlDataSource를 GridView 컨트롤에 데이터 바인딩했다면 DataSet 모드를 선택했을 것입니다. 그러나 DropDownList의 경우 DataReader 모드가 올바른 선택입니다.

참고

SqlDataSource 또는 AccessDataSource를 캐싱할 때 DataSourceMode 속성을 DataSet로 설정해야 합니다. DataReader의 DataSourceMode를 사용하여 캐싱을 사용하도록 설정하면 예외가 발생합니다.

SqlDataSource 속성

다음은 SqlDataSource 컨트롤의 몇 가지 속성입니다.

CancelSelectOnNullParameter

매개 변수 중 하나가 null인 경우 select 명령이 취소되는지 여부를 지정하는 부울 값입니다. 기본적으로 true입니다.

ConflictDetection

여러 사용자가 동시에 데이터 원본을 업데이트할 수 있는 상황에서 ConflictDetection 속성은 SqlDataSource 컨트롤의 동작을 결정합니다. 이 속성은 ConflictOptions 열거형 값 중 하나로 평가됩니다. 이러한 값은 CompareAllValuesOverwriteChanges입니다. OverwriteChanges로 설정하면 데이터 원본에 데이터를 마지막으로 쓰는 사람이 이전 변경 내용을 덮어씁니다. 그러나 ConflictDetection 속성이 CompareAllValues로 설정된 경우 SelectCommand에서 반환된 열에 대한 매개 변수가 생성되고 각 열에 원래 값을 저장하도록 매개 변수도 만들어집니다. 그러면 SqlDataSource가 SelectCommand가 실행된 이후 값이 변경되었는지 여부를 확인할 수 있습니다.

DeleteCommand

데이터베이스에서 행을 삭제할 때 사용되는 SQL 문자열을 설정하거나 가져옵니다. SQL 쿼리 또는 저장 프로시저 이름일 수 있습니다.

DeleteCommandType

SQL 쿼리(텍스트) 또는 저장 프로시저(StoredProcedure)와 같은 delete 명령 유형을 설정하거나 가져옵니다.

DeleteParameters

SqlDataSource 컨트롤과 연결된 SqlDataSourceView 개체의 DeleteCommand에서 사용하는 매개 변수를 반환합니다.

OldValuesParameterFormatString

이 속성은 ConflictDetection 속성이 CompareAllValues로 설정된 경우 원래 값 매개 변수의 형식을 지정하는 데 사용됩니다. 기본값은 {0} 원래 값 매개 변수가 원래 매개 변수와 동일한 이름을 사용한다는 의미입니다. 즉, 필드 이름이 EmployeeID이면 원래 값 매개 변수는 입니다 @EmployeeID.

SelectCommand

데이터베이스에서 데이터를 검색하는 데 사용되는 SQL 문자열을 설정하거나 가져옵니다. SQL 쿼리 또는 저장 프로시저 이름일 수 있습니다.

CommandType을 선택합니다.

SQL 쿼리(텍스트) 또는 저장 프로시저(StoredProcedure)와 같은 select 명령의 형식을 설정하거나 가져옵니다.

매개 변수 선택

SqlDataSource 컨트롤과 연결된 SqlDataSourceView 개체의 SelectCommand에서 사용하는 매개 변수를 반환합니다.

SortParameterName

데이터 소스 컨트롤에서 검색한 데이터를 정렬할 때 사용되는 저장 프로시저 매개 변수의 이름을 가져오거나 설정합니다. SelectCommandType이 StoredProcedure로 설정된 경우에만 유효합니다.

SqlCacheDependency

SQL Server 캐시 종속성에 사용되는 데이터베이스 및 테이블을 지정하는 세미콜론으로 구분된 문자열입니다. (SQL 캐시 종속성은 이후 모듈에서 설명합니다.)

UpdateCommand

데이터베이스에서 데이터를 업데이트할 때 사용되는 SQL 문자열을 설정하거나 가져옵니다. SQL 쿼리 또는 저장 프로시저 이름일 수 있습니다.

UpdateCommandType

SQL 쿼리(텍스트) 또는 저장 프로시저(StoredProcedure)와 같은 업데이트 명령 유형을 설정하거나 가져옵니다.

UpdateParameters

SqlDataSource 컨트롤과 연결된 SqlDataSourceView 개체의 UpdateCommand에서 사용하는 매개 변수를 반환합니다.

AccessDataSource 컨트롤

AccessDataSource 컨트롤은 SqlDataSource 클래스에서 파생되며 Microsoft Access 데이터베이스에 데이터를 바인딩하는 데 사용됩니다. AccessDataSource 컨트롤에 대한 ConnectionString 속성은 읽기 전용 속성입니다. ConnectionString 속성을 사용하는 대신 DataFile 속성을 사용하여 아래와 같이 Access Database를 가리킵니다.

<asp:AccessDataSource id="AccessDataSource1" runat="server" DataFile="~/App_Data/Northwind.mdb"> </asp:AccessDataSource>

AccessDataSource는 항상 기본 SqlDataSource의 ProviderName을 System.Data.OleDb로 설정하고 Microsoft.Jet.OLEDB.4.0 OLE DB 공급자를 사용하여 데이터베이스에 연결합니다. AccessDataSource 컨트롤을 사용하여 암호로 보호된 Access 데이터베이스에 연결할 수 없습니다. 암호로 보호된 데이터베이스에 연결해야 하는 경우 SqlDataSource 컨트롤을 사용해야 합니다.

참고

웹 사이트 내에 저장된 액세스 데이터베이스는 App_Data 디렉터리에 배치해야 합니다. ASP.NET 이 디렉터리의 파일을 검색할 수 없습니다. Access 데이터베이스를 사용할 때 프로세스 계정에 App_Data 디렉터리에 읽기 및 쓰기 권한을 부여해야 합니다.

XmlDataSource 컨트롤

XmlDataSource는 데이터 바인딩된 컨트롤에 XML 데이터를 바인딩하는 데 사용됩니다. DataFile 속성을 사용하여 XML 파일에 바인딩하거나 Data 속성을 사용하여 XML 문자열에 바인딩할 수 있습니다. XmlDataSource는 XML 특성을 바인딩 가능한 필드로 노출합니다. 특성으로 표시되지 않는 값에 바인딩해야 하는 경우 XSL 변환을 사용해야 합니다. XPath 식을 사용하여 XML 데이터를 필터링할 수도 있습니다.

다음 XML 파일을 고려합니다.

<?xml version="1.0" encoding="utf-8" ?> <People> <Person FirstName="Jake" LastName="Stone"> <Address> <Street>345 Maple St.</Street> <City>Redmond</City> <Region>WA</Region> <ZipCode>01434</ZipCode> </Address> <Job> <Title>CEO</Title> <Description>Develops company strategies.</Description> </Job> </Person> <Person FirstName="Jacob" LastName="Ladder"> <Address> <Street>123 Elm St.</Street> <City>Seattle</City> <Region>WA</Region> <ZipCode>11223</ZipCode> </Address> <Job> <Title>Attorney</Title> <Description>Reviews legal issues.</Description> </Job> </Person> <Person FirstName="Angela" LastName="Hound"> <Address> <Street>34 Palm Avenue</Street> <City>Renton</City> <Region>WA</Region> <ZipCode>63910</ZipCode> </Address> <Job> <Title>IT Director</Title> <Description>In charge of corporate network.</Description> </Job> </Person> </People>

XmlDataSource는 Person 노드만 <필터링하기 위해 사람/Person>의 XPath 속성을 사용합니다. 그런 다음 DropDownList는 DataTextField 속성을 사용하여 LastName 특성에 데이터를 바인딩합니다.

XmlDataSource 컨트롤은 주로 읽기 전용 XML 데이터에 데이터를 바인딩하는 데 사용되지만 XML 데이터 파일을 편집할 수 있습니다. 이러한 경우 XML 파일의 정보 자동 삽입, 업데이트 및 삭제는 다른 데이터 원본 컨트롤과 마찬가지로 자동으로 수행되지 않습니다. 대신 XmlDataSource 컨트롤의 다음 메서드를 사용하여 데이터를 수동으로 편집하는 코드를 작성해야 합니다.

GetXmlDocument

XmlDataSource에서 검색한 XML 코드를 포함하는 XmlDocument 개체를 검색합니다.

저장

메모리 내 XmlDocument를 데이터 원본에 다시 저장합니다.

Save 메서드는 다음 두 조건이 충족되는 경우에만 작동합니다.

  1. XmlDataSource는 DataFile 속성을 사용하여 메모리 내 XML 데이터에 바인딩할 Data 속성 대신 XML 파일에 바인딩합니다.
  2. Transform 또는 TransformFile 속성을 통해 변환을 지정하지 않습니다.

또한 Save 메서드는 여러 사용자가 동시에 호출할 때 예기치 않은 결과를 생성할 수 있습니다.

ObjectDataSource 컨트롤

지금까지 설명한 데이터 원본 컨트롤은 데이터 원본 제어가 데이터 저장소와 직접 통신하는 2계층 애플리케이션에 적합합니다. 그러나 많은 실제 애플리케이션은 데이터 원본 제어가 비즈니스 개체와 통신해야 할 수 있는 다중 계층 애플리케이션이며, 이 애플리케이션은 데이터 계층과 통신합니다. 이러한 상황에서 ObjectDataSource는 청구서를 멋지게 채웁니다. ObjectDataSource는 원본 개체와 함께 작동합니다. ObjectDataSource 컨트롤은 원본 개체의 instance 만들고, 지정된 메서드를 호출하고, 개체에 정적 메서드 대신 instance 메서드가 있는 경우 단일 요청의 scope 내에서 개체 instance 모두 삭제합니다(Visual Basic에서 공유됨). 따라서 개체는 상태 비 상태여야 합니다. 즉, 개체는 단일 요청 범위 내에서 필요한 모든 리소스를 획득하고 해제해야 합니다. ObjectDataSource 컨트롤의 ObjectCreating 이벤트를 처리하여 원본 개체를 만드는 방법을 제어할 수 있습니다. 원본 개체의 instance 만든 다음 ObjectDataSourceEventArgs 클래스의 ObjectInstance 속성을 해당 instance 설정할 수 있습니다. ObjectDataSource 컨트롤은 자체적으로 instance 만드는 대신 ObjectCreating 이벤트에서 만든 instance 사용합니다.

ObjectDataSource 컨트롤의 원본 개체가 데이터를 검색하고 수정하기 위해 호출할 수 있는 공용 정적 메서드(Visual Basic에서 공유됨)를 노출하는 경우 ObjectDataSource 컨트롤은 해당 메서드를 직접 호출합니다. ObjectDataSource 컨트롤이 메서드를 호출하기 위해 원본 개체의 instance 만들어야 하는 경우 개체에는 매개 변수를 사용하지 않는 공용 생성자가 포함되어야 합니다. ObjectDataSource 컨트롤은 원본 개체의 새 instance 만들 때 이 생성자를 호출합니다.

원본 개체에 매개 변수가 없는 공용 생성자가 없는 경우 ObjectCreating 이벤트의 ObjectDataSource 컨트롤에서 사용할 원본 개체의 instance 만들 수 있습니다.

개체 메서드 지정

ObjectDataSource 컨트롤의 원본 개체에는 데이터를 선택, 삽입, 업데이트 또는 삭제하는 데 사용되는 여러 메서드가 포함될 수 있습니다. 이러한 메서드는 ObjectDataSource 컨트롤의 SelectMethod, InsertMethod, UpdateMethod 또는 DeleteMethod 속성을 사용하여 식별되는 메서드의 이름을 기반으로 ObjectDataSource 컨트롤에 의해 호출됩니다. 원본 개체에는 SelectCountMethod 속성을 사용하여 ObjectDataSource 컨트롤로 식별되는 선택적 SelectCount 메서드가 포함될 수도 있습니다. 이 메서드는 데이터 원본의 총 개체 수를 반환합니다. ObjectDataSource 컨트롤은 페이징할 때 사용할 데이터 원본의 총 레코드 수를 검색하기 위해 Select 메서드가 호출된 후 SelectCount 메서드를 호출합니다.

데이터 원본 컨트롤을 사용하는 랩

연습 1 - SqlDataSource 컨트롤을 사용하여 데이터 표시

다음 연습에서는 SqlDataSource 컨트롤을 사용하여 Northwind 데이터베이스에 연결합니다. SQL Server 2000 instance Northwind 데이터베이스에 액세스할 수 있다고 가정합니다.

  1. 새 ASP.NET 웹 사이트 만들기

  2. 새 web.config 파일을 추가합니다.

    1. 솔루션 탐색기 프로젝트를 마우스 오른쪽 단추로 클릭하고 새 항목 추가를 클릭합니다.
    2. 템플릿 목록에서 웹 구성 파일을 선택하고 추가를 클릭합니다.
  3. <connectionStrings 섹션을> 다음과 같이 편집합니다.

    <asp:SqlDataSource ID="SqlDataSource1" runat="server"
        ConnectionString="<%$ConnectionStrings:Northwind%>"
        SelectCommand="SELECT * FROM Products">
    </asp:SqlDataSource>
    
  4. 코드 보기로 전환하고 다음과 같이 ConnectionString 특성 및 SelectCommand 특성을 <asp:SqlDataSource> 컨트롤에 추가합니다.

    <asp:SqlDataSource ID="SqlDataSource1" runat="server"
        ConnectionString="<%$ConnectionStrings:Northwind%>"
        SelectCommand="SELECT * FROM Products">
    </asp:SqlDataSource>
    
  5. 디자인 보기에서 새 GridView 컨트롤을 추가합니다.

  6. GridView 작업 메뉴의 데이터 원본 선택 드롭다운에서 SqlDataSource1을 선택합니다.

  7. Default.aspx를 마우스 오른쪽 단추로 클릭하고 메뉴에서 브라우저에서 보기를 선택합니다. 저장하라는 메시지가 표시되면 예를 클릭합니다.

  8. GridView는 Products 테이블의 데이터를 표시합니다.

연습 2 - SqlDataSource 컨트롤을 사용하여 데이터 편집

다음 연습에서는 선언적 구문을 사용하여 DropDownList 컨트롤을 데이터 바인딩하는 방법을 보여 줍니다. 그러면 DropDownList 컨트롤에 제공된 데이터를 편집할 수 있습니다.

  1. 디자인 보기에서 Default.aspx에서 GridView 컨트롤을 삭제합니다.

    중요: 페이지에 SqlDataSource 컨트롤을 그대로 둡니다.

  2. DropDownList 컨트롤을 Default.aspx에 추가합니다.

  3. 원본 보기로 전환합니다.

  4. 다음과 같이 DataSourceId, DataTextField 및 DataValueField 특성을 <asp:DropDownList> 컨트롤에 추가합니다.

    <asp:DropDownList ID="ddlProducts" runat="server"
         DataSourceId="SqlDataSource1" DataTextField="ProductName"
         DataValueField="ProductID">
    </asp:DropDownList>
    
  5. Default.aspx를 저장하고 브라우저에서 봅니다. DropDownList에는 Northwind 데이터베이스의 모든 제품이 포함되어 있습니다.

  6. 브라우저를 닫습니다.

  7. Default.aspx의 원본 보기에서 DropDownList 컨트롤 아래에 새 TextBox 컨트롤을 추가합니다. TextBox의 ID 속성을 txtProductName으로 변경합니다.

  8. TextBox 컨트롤 아래에서 새 단추 컨트롤을 추가합니다. Button의 ID 속성을 btnUpdate로 변경하고 Text 속성을 제품 이름 업데이트로 변경합니다.

  9. Default.aspx의 원본 보기에서 다음과 같이 UpdateCommand 속성과 두 개의 새 UpdateParameters를 SqlDataSource 태그에 추가합니다.

    <asp:SqlDataSource ID="SqlDataSource1" runat="server"
        ConnectionString="<%$ConnectionStrings:Northwind%>"
        SelectCommand="SELECT * FROM Products"
        UpdateCommand="UPDATE Products SET ProductName=@ProductName WHERE ProductID=@ProductID">
          <UpdateParameters>
          <asp:ControlParameter Name="ProductName" 
            ControlID="txtProductName" PropertyName="Text" />
          <asp:ControlParameter Name="ProductID" 
            ControlID="ddlProducts" PropertyName="SelectedValue" />
    </asp:SqlDataSource>
    

    참고

    이 코드에는 두 개의 업데이트 매개 변수(ProductName 및 ProductID)가 추가되었습니다. 이러한 매개 변수는 txtProductName TextBox의 Text 속성과 ddlProducts DropDownList의 SelectedValue 속성에 매핑됩니다.

  10. 디자인 보기로 전환하고 단추 컨트롤을 두 번 클릭하여 이벤트 처리기를 추가합니다.

  11. btnUpdate_Click 코드에 다음 코드를 추가합니다.

    SqlDataSource1.Update();
    
  12. Default.aspx를 마우스 오른쪽 단추로 클릭하고 브라우저에서 보도록 선택합니다. 모든 변경 내용을 저장하라는 메시지가 표시되면 예를 클릭합니다.

  13. ASP.NET 2.0 부분 클래스는 런타임에 컴파일할 수 있습니다. 코드 변경 내용이 적용되는지 확인하기 위해 애플리케이션을 빌드할 필요는 없습니다.

  14. DropDownList에서 제품을 선택합니다.

  15. TextBox에서 선택한 제품의 새 이름을 입력한 다음 업데이트 단추를 클릭합니다.

  16. 제품 이름이 데이터베이스에서 업데이트됩니다.

연습 3 ObjectDataSource 컨트롤 사용

이 연습에서는 ObjectDataSource 컨트롤과 원본 개체를 사용하여 Northwind 데이터베이스와 상호 작용하는 방법을 보여 줍니다.

  1. 솔루션 탐색기 프로젝트를 마우스 오른쪽 단추로 클릭하고 새 항목 추가를 클릭합니다.

  2. 템플릿 목록에서 웹 양식을 선택합니다. 이름을 object.aspx로 변경하고 추가를 클릭합니다.

  3. 솔루션 탐색기 프로젝트를 마우스 오른쪽 단추로 클릭하고 새 항목 추가를 클릭합니다.

  4. 템플릿 목록에서 클래스를 선택합니다. 클래스 이름을 NorthwindData.cs로 변경하고 추가를 클릭합니다.

  5. 클래스를 App_Code 폴더에 추가하라는 메시지가 표시되면 예를 클릭합니다.

  6. NorthwindData.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;
    using System.Data.SqlClient;
    public class NorthwindData {
        private string _connectionString;
        public NorthwindData() {
            Initialize();
        }
    
        private void Initialize() {
            if (ConfigurationManager.ConnectionStrings["Northwind"] == null ||
                ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString.Trim() == "") {
                    throw new Exception("A connection string named 'Northwind' with " +
                    "a valid connection string must exist in the <connectionStrings> " +
                    "configuration section for the application.");
            }
            _connectionString = ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;
        }
    
        public DataTable GetAllEmployees(string sortColumns, int startRecord, int maxRecords) {
            VerifySortColumns(sortColumns);
            string sqlCmd = "SELECT EmployeeID, LastName, FirstName, Address, " +
                "City, Region, PostalCode FROM Employees ";
            if (sortColumns.Trim() == "")
                sqlCmd += "ORDER BY EmployeeID";
            else
                sqlCmd += "ORDER BY " + sortColumns;
    
            SqlConnection conn = new SqlConnection(_connectionString);
            SqlDataAdapter da = new SqlDataAdapter(sqlCmd, conn);
            DataSet ds = new DataSet();
            try {
                conn.Open();
                da.Fill(ds, startRecord, maxRecords, "Employees");
            } catch (SqlException e) {
                // Handle exception.
            } finally {
                conn.Close();
            }
            return ds.Tables["Employees"];
        }
    
        public int SelectCount() {
            SqlConnection conn = new SqlConnection(_connectionString);
            SqlCommand cmd = new SqlCommand("SELECT COUNT(*) FROM Employees", conn);
            int result = 0;
    
            try {
                conn.Open();
                result = (int)cmd.ExecuteScalar();
            } catch (SqlException e) {
                // Handle exception.
            } finally {
                conn.Close();
            }
            return result;
        }
    
        //////////
        // Verify that only valid columns are specified in the sort expression to
        // avoid a SQL Injection attack.
        private void VerifySortColumns(string sortColumns) {
            if (sortColumns.ToLowerInvariant().EndsWith(" desc"))
                sortColumns = sortColumns.Substring(0, sortColumns.Length - 5);
            string[] columnNames = sortColumns.Split(',');
            foreach (string columnName in columnNames) {
                switch (columnName.Trim().ToLowerInvariant()) {
                    case "employeeid":
                        break;
                    case "lastname":
                        break;
                    case "firstname":
                        break;
                    case "":
                        break;
                    default:
                        throw new ArgumentException("SortColumns contains an " +
                            "invalid column name.");
                        break;
                }
            }
        }
    
        // Select an employee.
        public DataTable GetEmployee(int EmployeeID) {
            SqlConnection conn = new SqlConnection(_connectionString);
            SqlDataAdapter da =
                new SqlDataAdapter("SELECT EmployeeID, LastName, FirstName, " +
                "Address, City, Region, PostalCode " +
                " FROM Employees WHERE EmployeeID = @EmployeeID", conn);
            da.SelectCommand.Parameters.Add("@EmployeeID", SqlDbType.Int).Value = EmployeeID;
            DataSet ds = new DataSet();
            try {
                conn.Open();
                da.Fill(ds, "Employees");
            } catch (SqlException e) {
                // Handle exception.
            } finally {
                conn.Close();
            }
    
            return ds.Tables["Employees"];
        }
    
        // Delete the Employee by ID.
        public int DeleteEmployee(int EmployeeID) {
             SqlConnection conn = new SqlConnection(_connectionString);
             SqlCommand cmd = new SqlCommand("DELETE FROM Employees WHERE " +
                 "EmployeeID = @EmployeeID", conn);
             cmd.Parameters.Add("@EmployeeID", SqlDbType.Int).Value = EmployeeID;
             int result = 0;
             try {
                 conn.Open();
                 result = cmd.ExecuteNonQuery();
             } catch (SqlException e) {
                 // Handle exception.
             } finally {
                 conn.Close();
             }
    
             return result;
         }
    
         // Update the Employee by original ID.
         public int UpdateEmployee(int EmployeeID, string LastName, string FirstName,
             string Address, string City, string Region,
             string PostalCode) {
             if (String.IsNullOrEmpty(FirstName))
                 throw new ArgumentException("FirstName cannot be null or an empty string.");
             if (String.IsNullOrEmpty(LastName))
                 throw new ArgumentException("LastName cannot be null or an empty string.");
             if (Address == null) { Address = String.Empty; }
             if (City == null) { City = String.Empty; }
             if (Region == null) { Region = String.Empty; }
             if (PostalCode == null) { PostalCode = String.Empty; }
    
             SqlConnection conn = new SqlConnection(_connectionString);
             SqlCommand cmd = new SqlCommand("UPDATE Employees " +
                 " SET FirstName=@FirstName, " +
                 "LastName=@LastName, " +
                 "Address=@Address, City=@City, " +
                 "Region=@Region, " +
                 "PostalCode=@PostalCode " +
                 "WHERE EmployeeID=@EmployeeID", conn);
             cmd.Parameters.Add("@FirstName", SqlDbType.VarChar, 10).Value = FirstName;
             cmd.Parameters.Add("@LastName", SqlDbType.VarChar, 20).Value = LastName;
             cmd.Parameters.Add("@Address", SqlDbType.VarChar, 60).Value = Address;
             cmd.Parameters.Add("@City", SqlDbType.VarChar, 15).Value = City;
             cmd.Parameters.Add("@Region", SqlDbType.VarChar, 15).Value = Region;
             cmd.Parameters.Add("@PostalCode", SqlDbType.VarChar, 10).Value = PostalCode;
             cmd.Parameters.Add("@EmployeeID", SqlDbType.Int).Value = EmployeeID;
    
             int result = 0;
             try {
                 conn.Open();
                 result = cmd.ExecuteNonQuery();
             } catch (SqlException e) {
                 // Handle exception.
             } finally {
                 conn.Close();
             }
    
             return result;
        }
    
        // Insert an Employee.
        public int InsertEmployee(string LastName, string FirstName,
            string Address, string City, string Region,
            string PostalCode) {
            if (String.IsNullOrEmpty(FirstName))
                throw new ArgumentException("FirstName cannot be null or an empty string.");
            if (String.IsNullOrEmpty(LastName))
                throw new ArgumentException("LastName cannot be null or an empty string.");
            if (Address == null) { Address = String.Empty; }
            if (City == null) { City = String.Empty; }
            if (Region == null) { Region = String.Empty; }
            if (PostalCode == null) { PostalCode = String.Empty; }
    
            SqlConnection conn = new SqlConnection(_connectionString);
            SqlCommand cmd = new SqlCommand("INSERT INTO Employees " +
                " (FirstName, LastName, Address, " +
                " City, Region, PostalCode) " +
                " Values(@FirstName, @LastName, " +
                "@Address, @City, @Region, @PostalCode); " +
                "SELECT @EmployeeID = SCOPE_IDENTITY()", conn);
    
            cmd.Parameters.Add("@FirstName", SqlDbType.VarChar, 10).Value = FirstName;
            cmd.Parameters.Add("@LastName", SqlDbType.VarChar, 20).Value = LastName;
            cmd.Parameters.Add("@Address", SqlDbType.VarChar, 60).Value = Address;
            cmd.Parameters.Add("@City", SqlDbType.VarChar, 15).Value = City;
            cmd.Parameters.Add("@Region", SqlDbType.VarChar, 15).Value = Region;
            cmd.Parameters.Add("@PostalCode", SqlDbType.VarChar, 10).Value = PostalCode;
            SqlParameter p = cmd.Parameters.Add("@EmployeeID", SqlDbType.Int);
                p.Direction = ParameterDirection.Output;
            int newEmployeeID = 0;
            try {
                conn.Open();
                cmd.ExecuteNonQuery();
                newEmployeeID = (int)p.Value;
            } catch (SqlException e) {
                // Handle exception.
            } finally {
                conn.Close();
            }
    
            return newEmployeeID;
        }
    
        //
        // Methods that support Optimistic Concurrency checks.
        //
        // Delete the Employee by ID.
        public int DeleteEmployee(int original_EmployeeID, string original_LastName,
            string original_FirstName, string original_Address,
            string original_City, string original_Region,
            string original_PostalCode) {
    
            if (String.IsNullOrEmpty(original_FirstName))
                throw new ArgumentException("FirstName cannot be null or an empty string.");
            if (String.IsNullOrEmpty(original_LastName))
                throw new ArgumentException("LastName cannot be null or an empty string.");
            if (original_Address == null) { original_Address = String.Empty; }
            if (original_City == null) { original_City = String.Empty; }
            if (original_Region == null) { original_Region = String.Empty; }
            if (original_PostalCode == null) { original_PostalCode = String.Empty; }
            string sqlCmd = "DELETE FROM Employees WHERE EmployeeID = " + @original_EmployeeID
    
            SqlConnection conn = new SqlConnection(_connectionString);
            SqlCommand cmd = new SqlCommand(sqlCmd, conn);
            cmd.Parameters.Add("@original_EmployeeID",
                SqlDbType.Int).Value = original_EmployeeID;
            cmd.Parameters.Add("@original_FirstName",
                SqlDbType.VarChar, 10).Value = original_FirstName;
            cmd.Parameters.Add("@original_LastName",
                SqlDbType.VarChar, 20).Value = original_LastName;
            cmd.Parameters.Add("@original_Address",
                SqlDbType.VarChar, 60).Value = original_Address;
            cmd.Parameters.Add("@original_City",
                SqlDbType.VarChar, 15).Value = original_City;
            cmd.Parameters.Add("@original_Region",
                SqlDbType.VarChar, 15).Value = original_Region;
            cmd.Parameters.Add("@original_PostalCode",
                SqlDbType.VarChar, 10).Value = original_PostalCode;
    
            int result = 0;
            try {
                conn.Open();
                result = cmd.ExecuteNonQuery();
            } catch (SqlException e) {
                // Handle exception.
            } finally {
                conn.Close();
            }
    
            return result;
        }
    
        // Update the Employee by original ID.
        public int UpdateEmployee(string LastName, string FirstName,
            string Address, string City, string Region,
            string PostalCode, int original_EmployeeID,
            string original_LastName, string original_FirstName,
            string original_Address, string original_City,
            string original_Region, string original_PostalCode) {
    
            if (String.IsNullOrEmpty(FirstName))
                throw new ArgumentException("FirstName cannot be null or an empty string.");
            if (String.IsNullOrEmpty(LastName))
                throw new ArgumentException("LastName cannot be null or an empty string.");
            if (Address == null) { Address = String.Empty; }
            if (City == null) { City = String.Empty; }
            if (Region == null) { Region = String.Empty; }
            if (PostalCode == null) { PostalCode = String.Empty; }
            if (original_Address == null) { original_Address = String.Empty; }
            if (original_City == null) { original_City = String.Empty; }
            if (original_Region == null) { original_Region = String.Empty; }
            if (original_PostalCode == null) { original_PostalCode = String.Empty; }
    
            string sqlCmd = "UPDATE Employees " +
                " SET FirstName = @FirstName, LastName = @LastName, " +
                " Address = @Address, City = @City, Region = @Region, " +
                " PostalCode = @PostalCode " +
                " WHERE EmployeeID = @original_EmployeeID";
    
            SqlConnection conn = new SqlConnection(_connectionString);
            SqlCommand cmd = new SqlCommand(sqlCmd, conn);
            cmd.Parameters.Add("@FirstName", SqlDbType.VarChar, 10).Value = FirstName;
            cmd.Parameters.Add("@LastName", SqlDbType.VarChar, 20).Value = LastName;
            cmd.Parameters.Add("@Address", SqlDbType.VarChar, 60).Value = Address;
            cmd.Parameters.Add("@City", SqlDbType.VarChar, 15).Value = City;
            cmd.Parameters.Add("@Region", SqlDbType.VarChar, 15).Value = Region;
            cmd.Parameters.Add("@PostalCode", SqlDbType.VarChar, 10).Value = PostalCode;
            cmd.Parameters.Add("@original_EmployeeID",
                SqlDbType.Int).Value = original_EmployeeID;
            cmd.Parameters.Add("@original_FirstName",
                SqlDbType.VarChar, 10).Value = original_FirstName;
            cmd.Parameters.Add("@original_LastName",
                SqlDbType.VarChar, 20).Value = original_LastName;
            cmd.Parameters.Add("@original_Address",
                SqlDbType.VarChar, 60).Value = original_Address;
            cmd.Parameters.Add("@original_City",
                SqlDbType.VarChar, 15).Value = original_City;
            cmd.Parameters.Add("@original_Region",
                SqlDbType.VarChar, 15).Value = original_Region;
            cmd.Parameters.Add("@original_PostalCode",
                SqlDbType.VarChar, 10).Value = original_PostalCode;
    
            int result = 0;
    
            try {
                conn.Open();
                result = cmd.ExecuteNonQuery();
            } catch (SqlException e) {
                // Handle exception.
            } finally {
                conn.Close();
            }
            return result;
        }
    }
    
  7. object.aspx의 원본 뷰에 다음 코드를 추가합니다.

    <%@ Page language="C#" %>
    <script RunAt="server">
    void EmployeesDetailsView_ItemInserted(Object sender, DetailsViewInsertedEventArgs e) {
        EmployeesGridView.DataBind();
    }
    
    void EmployeesDetailsView_ItemUpdated(Object sender, DetailsViewUpdatedEventArgs e) {
        EmployeesGridView.DataBind();
    }
    
    void EmployeesDetailsView_ItemDeleted(Object sender, DetailsViewDeletedEventArgs e) {
        EmployeesGridView.DataBind();
    }
    void EmployeesGridView_OnSelectedIndexChanged(object sender, EventArgs e) {
        EmployeeDetailsObjectDataSource.SelectParameters["EmployeeID"].DefaultValue =
            EmployeesGridView.SelectedDataKey.Value.ToString();
        EmployeesDetailsView.DataBind();
    }
    void EmployeeDetailsObjectDataSource_OnInserted(object sender,
        ObjectDataSourceStatusEventArgs e) {
    
        EmployeeDetailsObjectDataSource.SelectParameters["EmployeeID"].DefaultValue =
            e.ReturnValue.ToString();
        EmployeesDetailsView.DataBind();
    }
    void EmployeeDetailsObjectDataSource_OnUpdated(object sender,
        ObjectDataSourceStatusEventArgs e) {
    
        if ((int)e.ReturnValue == 0)
            Msg.Text = "Employee was not updated. Please try again.";
    }
    void EmployeeDetailsObjectDataSource_OnDeleted(object sender,
        ObjectDataSourceStatusEventArgs e) {
    
        if ((int)e.ReturnValue == 0)
            Msg.Text = "Employee was not deleted. Please try again.";
    }
    void Page_Load() {
        Msg.Text = "";
    }
    </script>
    <html>
      <body>
        <form id="Form1" runat="server">
          <h3>ObjectDataSource Example</h3>
          <asp:Label id="Msg" runat="server" ForeColor="Red" />
          <asp:ObjectDataSource
              ID="EmployeesObjectDataSource"
              runat="server"
              TypeName="NorthwindData"
              SortParameterName="SortColumns"
              EnablePaging="true"
              SelectCountMethod="SelectCount"
              StartRowIndexParameterName="StartRecord"
              MaximumRowsParameterName="MaxRecords"
              SelectMethod="GetAllEmployees" >
          </asp:ObjectDataSource>
          <asp:ObjectDataSource
              ID="EmployeeDetailsObjectDataSource"
              runat="server"
              TypeName="NorthwindData"
              ConflictDetection="CompareAllValues"
              OldValuesParameterFormatString="{0}"
              SelectMethod="GetEmployee"
              InsertMethod="InsertEmployee"
              UpdateMethod="UpdateEmployee"
              DeleteMethod="DeleteEmployee"
              OnInserted="EmployeeDetailsObjectDataSource_OnInserted"
              OnUpdated="EmployeeDetailsObjectDataSource_OnUpdated"
              OnDeleted="EmployeeDetailsObjectDataSource_OnDeleted">
              <SelectParameters>
                  <asp:Parameter Name="EmployeeID" Type="Int32" />
              </SelectParameters>
          </asp:ObjectDataSource>
          <table cellspacing="10">
            <tr>
              <td valign="top">
                <asp:GridView ID="EmployeesGridView"
                    DataSourceID="EmployeesObjectDataSource"
                    AutoGenerateColumns="false"
                    AllowSorting="true"
                    AllowPaging="true"
                    PageSize="5"
                    DataKeyNames="EmployeeID"
                    OnSelectedIndexChanged="EmployeesGridView_OnSelectedIndexChanged"
                    RunAt="server">
                    <HeaderStyle backcolor="lightblue" forecolor="black"/>
                    <Columns>
                    <asp:ButtonField Text="Details..."
                    HeaderText="Show Details"
                    CommandName="Select"/>
    
                    <asp:BoundField DataField="EmployeeID" HeaderText="Employee ID"
                    SortExpression="EmployeeID" />
                    <asp:BoundField DataField="FirstName" HeaderText="First Name"
                    SortExpression="FirstName" />
                    <asp:BoundField DataField="LastName" HeaderText="Last Name"
                    SortExpression="LastName, FirstName" />
                    </Columns>
                </asp:GridView>
              </td>
              <td valign="top">
                <asp:DetailsView ID="EmployeesDetailsView"
                    DataSourceID="EmployeeDetailsObjectDataSource"
                    AutoGenerateRows="false"
                    EmptyDataText="No records."
                    DataKeyNames="EmployeeID"
                    Gridlines="Both"
                    AutoGenerateInsertButton="true"
                    AutoGenerateEditButton="true"
                    AutoGenerateDeleteButton="true"
                    OnItemInserted="EmployeesDetailsView_ItemInserted"
                    OnItemUpdated="EmployeesDetailsView_ItemUpdated"
                    OnItemDeleted="EmployeesDetailsView_ItemDeleted"
                    RunAt="server">
                    <HeaderStyle backcolor="Navy" forecolor="White"/>
                    <RowStyle backcolor="White"/>
                    <AlternatingRowStyle backcolor="LightGray"/>
                    <EditRowStyle backcolor="LightCyan"/>
                    <Fields>
                        <asp:BoundField DataField="EmployeeID" HeaderText="Employee ID"
                            InsertVisible="False" ReadOnly="true"/>
                        <asp:BoundField DataField="FirstName" HeaderText="First Name"/>
                        <asp:BoundField DataField="LastName" HeaderText="Last Name"/>
                        <asp:BoundField DataField="Address" HeaderText="Address"/>
                        <asp:BoundField DataField="City" HeaderText="City"/>
                        <asp:BoundField DataField="Region" HeaderText="Region"/>
                        <asp:BoundField DataField="PostalCode" HeaderText="Postal Code"/>
                    </Fields>
                  </asp:DetailsView>
                </td>
              </tr>
            </table>
          </form>
        </body>
      </html>
    
  8. 모든 파일을 저장하고 object.aspx를 찾습니다.

  9. 세부 정보를 보고, 직원을 편집하고, 직원을 추가하고, 직원을 삭제하여 인터페이스와 상호 작용합니다.