작성자: 스콧 미첼
데이터베이스를 사용하는 경우 여러 테이블에 분산된 데이터를 요청하는 것이 일반적입니다. 서로 다른 두 테이블에서 데이터를 검색하려면 상관 관계가 있는 하위 쿼리 또는 JOIN 작업을 사용할 수 있습니다. 이 자습서에서는 주 쿼리에 JOIN을 포함하는 TableAdapter를 만드는 방법을 살펴보기 전에 상관 관계가 있는 하위 쿼리와 JOIN 구문을 비교합니다.
소개
관계형 데이터베이스를 사용하면 작업하는 데 관심이 있는 데이터가 여러 테이블에 분산되는 경우가 많습니다. 예를 들어 제품 정보를 표시할 때 각 제품의 해당 범주 및 공급업체 이름을 나열하려고 할 수 있습니다. 테이블에는 Products
CategoryID
값과 SupplierID
값이 있지만 실제 범주와 공급자 이름은 Categories
테이블과 Suppliers
테이블에 각각 있습니다.
다른 관련 테이블에서 정보를 검색하려면 상관 관계가 있는 하위 쿼리 또는 JOIN
s를 사용할 수 있습니다. 상호 관련된 하위 쿼리는 외부 쿼리의 열을 참조하는 중첩 SELECT
된 쿼리입니다. 예를 들어 데이터 액세스 계층 만들기 자습서에서는 주 쿼리에서 ProductsTableAdapter
두 개의 상호 관련된 하위 쿼리를 사용하여 각 제품에 대한 범주 및 공급업체 이름을 반환했습니다. A JOIN
는 서로 다른 두 테이블의 관련 행을 병합하는 SQL 구문입니다.
JOIN
SqlDataSource 컨트롤 자습서와 함께 데이터 쿼리에서 각 제품과 함께 범주 정보를 표시했습니다.
TableAdapters에서 JOIN
s의 사용을 자제한 이유는 TableAdapter 마법사가 해당 INSERT
, UPDATE
, 및 DELETE
문을 자동으로 생성하는 데 제한이 있기 때문입니다. 특히 TableAdapter의 기본 쿼리에 어떠한 JOIN
가 포함되어 있는 경우, TableAdapter는 임시 SQL 문 또는 InsertCommand
, UpdateCommand
, DeleteCommand
속성에 대한 저장 프로시저를 자동으로 생성할 수 없습니다.
이 자습서에서는 JOIN
s 와 상호 관련된 하위 쿼리를 간략히 비교하고 대조한 후, 주요 쿼리에 JOIN
s 를 포함하는 TableAdapter 를 만드는 방법을 탐구합니다.
상호 관련된 하위 쿼리와 비교 및 대조하기
각 제품의 관련 범주 및 공급업체 이름을 가져오기 위해 상관 하위 쿼리를 사용하는 ProductsTableAdapter
DataSet의 첫 번째 자습서에서 만든 Northwind
항목을 기억하십시오.
ProductsTableAdapter
기본 쿼리는 다음과 같습니다.
SELECT ProductID, ProductName, SupplierID, CategoryID,
QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
ReorderLevel, Discontinued,
(SELECT CategoryName FROM Categories WHERE Categories.CategoryID =
Products.CategoryID) as CategoryName,
(SELECT CompanyName FROM Suppliers WHERE Suppliers.SupplierID =
Products.SupplierID) as SupplierName
FROM Products
두 개의 연관된 하위 쿼리 - (SELECT CategoryName FROM Categories WHERE Categories.CategoryID = Products.CategoryID)
와 (SELECT CompanyName FROM Suppliers WHERE Suppliers.SupplierID = Products.SupplierID)
- 는 외부 SELECT
문의 열 목록에 추가 열로 제품당 단일 값을 반환하는 SELECT
쿼리입니다.
JOIN
또는 각 제품의 공급업체 및 범주 이름을 반환하는 데 사용할 수 있습니다. 다음 쿼리는 위의 출력과 동일한 출력을 반환하지만 하위 쿼리 대신 s를 사용합니다 JOIN
.
SELECT ProductID, ProductName, Products.SupplierID, Products.CategoryID,
QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
ReorderLevel, Discontinued,
Categories.CategoryName,
Suppliers.CompanyName as SupplierName
FROM Products
LEFT JOIN Categories ON
Categories.CategoryID = Products.CategoryID
LEFT JOIN Suppliers ON
Suppliers.SupplierID = Products.SupplierID
한 JOIN
테이블의 레코드를 일부 조건에 따라 다른 테이블의 레코드와 병합합니다. 예를 들어 LEFT JOIN Categories ON Categories.CategoryID = Products.CategoryID
위의 쿼리에서 SQL Server는 각 제품 레코드를 해당 값이 CategoryID
제품 CategoryID
값과 일치하는 범주 레코드와 병합하도록 지시합니다. 병합된 결과를 통해 각 제품에 대한 해당 범주 필드(예: CategoryName
)를 사용할 수 있습니다.
비고
JOIN
는 관계형 데이터베이스에서 데이터를 쿼리할 때 일반적으로 사용됩니다.
JOIN
구문을 처음 접하거나 사용법을 복습해야 한다면, W3 Schools의 SQL 조인 자습서를 추천합니다. 또한 JOIN
의 기본 사항 및 하위 쿼리 기본 사항 섹션도 읽을 가치가 있습니다.
JOIN
s 및 상관 관계 하위 쿼리를 사용하여 다른 테이블에서 관련 데이터를 검색할 수 있으므로 많은 개발자가 머리를 긁적거리고 어떤 방법을 사용할지 궁금해합니다. 내가 말한 모든 SQL 전문가는 SQL Server가 거의 동일한 실행 계획을 생성하기 때문에 성능 면에서 실제로 중요하지 않다고 말했습니다. 그런 다음, 사용자와 팀이 가장 편안하게 사용할 수 있는 기술을 사용하는 것이 그들의 조언입니다. 이 조언을 전달한 후, 이 전문가들은 즉시 상관 하위 쿼리보다 JOIN
를 선호한다는 것을 표현합니다.
Typed DataSets를 사용하여 데이터 액세스 계층을 빌드할 때 하위 쿼리를 사용할 때 도구가 더 잘 작동합니다. 특히 기본 쿼리에 INSERT
가 포함된 경우, TableAdapter 마법사는 해당 UPDATE
, DELETE
, 및 JOIN
문을 자동으로 생성하지 않지만, 상관 서브쿼리가 사용될 때 이러한 문들을 자동으로 생성합니다.
이 단점을 탐구하려면 ~/App_Code/DAL
폴더에 임시 타입 DataSet을 만듭니다. TableAdapter 구성 마법사 중에 임시 SQL 문을 사용하도록 선택하고 다음 SELECT
쿼리를 입력합니다(그림 1 참조).
SELECT ProductID, ProductName, Products.SupplierID, Products.CategoryID,
QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
ReorderLevel, Discontinued,
Categories.CategoryName,
Suppliers.CompanyName as SupplierName
FROM Products
LEFT JOIN Categories ON
Categories.CategoryID = Products.CategoryID
LEFT JOIN Suppliers ON
Suppliers.SupplierID = Products.SupplierID
그림 1: 포함된 JOIN
기본 쿼리 입력(전체 크기 이미지를 보려면 클릭)
기본적으로 TableAdapter는 기본 쿼리를 기반으로 INSERT
, UPDATE
, 및 DELETE
문을 자동으로 만듭니다. 고급 단추를 클릭하면 이 기능이 활성화된 것을 볼 수 있습니다. 이 설정에도 불구하고, 기본 쿼리에 INSERT
가 포함되어 있으므로 TableAdapter는 UPDATE
, DELETE
, 그리고 JOIN
문을 생성할 수 없습니다.
그림 2: 다음을 포함하는 JOIN
기본 쿼리 입력
마침을 클릭하여 마법사를 완료합니다. 이 시점에서 데이터 집합 디자이너에는 쿼리 열 목록에 반환된 각 필드를 위한 열이 있는 단일 데이터 테이블과 TableAdapter가 포함됩니다. 여기에는 CategoryName
및 SupplierName
이 포함되며, 그림 3에 보여집니다.
그림 3: DataTable에는 열 목록에 반환된 각 필드에 대한 열이 포함됩니다.
DataTable에는 적절한 열이 있지만, TableAdapter의 InsertCommand
, UpdateCommand
, 및 DeleteCommand
속성에 대한 값이 없습니다. 이를 확인하려면 디자이너에서 TableAdapter를 클릭한 다음 속성 창으로 이동합니다. 그러면 , InsertCommand
및 UpdateCommand
속성이 DeleteCommand
(None)으로 설정된 것을 볼 수 있습니다.
그림 4: InsertCommand
, UpdateCommand
및 DeleteCommand
속성이 (없음)으로 설정됨(전체 크기 이미지를 보려면 클릭)
이 단점을 해결하기 위해 속성 창을 통해 해당 및 속성에 대한 InsertCommand
UpdateCommand
SQL 문 및 DeleteCommand
매개 변수를 수동으로 제공할 수 있습니다. 또는 TableAdapter의 기본 쿼리를 구성하여 포함하지 않도록 s JOIN
를 구성할 수 있습니다. 이렇게 하면 INSERT
, UPDATE
및 DELETE
문이 자동으로 생성될 수 있습니다. 마법사를 완료한 후에는 속성 창에서 TableAdapter를 SelectCommand
수동으로 업데이트하여 JOIN
구문을 포함할 수 있습니다.
이 접근 방식은 작동하지만, 임시 SQL 쿼리를 사용할 때에는 매우 취약합니다. TableAdapter의 기본 쿼리가 마법사를 통해 다시 구성될 때마다 자동 생성된 INSERT
, UPDATE
, 및 DELETE
문이 재작성되기 때문입니다. 즉, TableAdapter를 마우스 오른쪽 단추로 클릭하고 상황에 맞는 메뉴에서 구성을 선택한 다음 마법사를 다시 완료하면 나중에 만든 모든 사용자 지정이 손실됩니다.
TableAdapter의 자동 생성 INSERT
, UPDATE
, 및 DELETE
명령문의 취약성은 다행히 임시 SQL 문으로 제한됩니다. TableAdapter에서 저장 프로시저를 사용하는 경우 저장 프로시저가 수정될 것을 두려워하지 않고 , SelectCommand
InsertCommand
또는 UpdateCommand
저장 프로시저를 사용자 지정DeleteCommand
하고 TableAdapter 구성 마법사를 다시 실행할 수 있습니다.
다음 몇 단계를 통해 처음에는 해당 삽입, 업데이트 및 삭제 저장 프로시저가 자동으로 생성되도록 모든 JOIN
항목을 생략하는 기본 쿼리를 사용하는 TableAdapter를 만듭니다. 관련 테이블에서 추가 열을 반환하는 SelectCommand
을 사용하도록 JOIN
을 업데이트합니다. 마지막으로 해당 비즈니스 논리 계층 클래스를 만들고 ASP.NET 웹 페이지에서 TableAdapter를 사용하는 방법을 보여 줍니다.
1단계: 간소화된 기본 쿼리를 사용하여 TableAdapter 만들기
이 자습서에서는 Employees
테이블에 대한 TableAdapter와 NorthwindWithSprocs
DataSet의 강력한 형식의 DataTable을 추가합니다.
Employees
테이블에는 직원 관리자의 ReportsTo
에 대해 지정한 EmployeeID
필드가 포함되어 있습니다. 예를 들어, 직원 앤 도즈워스의 ReportTo
값은 5이고, 이는 스티븐 뷰캐넌의 EmployeeID
값입니다. 결과적으로 앤은 매니저 스티븐에게 보고합니다. 각 직원의 ReportsTo
가치를 보고하는 것 외에도 관리자의 이름을 검색할 수도 있습니다. 이 작업은 .를 JOIN
사용하여 수행할 수 있습니다. 그러나 처음에 TableAdapter를 만들 때 사용하면 JOIN
마법사가 해당 삽입, 업데이트 및 삭제 기능을 자동으로 생성하지 못하게 합니다. 따라서 기본 쿼리에 s가 포함되지 JOIN
않은 TableAdapter를 만들어 시작합니다. 그런 다음, 2단계에서 기본 쿼리 저장 프로시저를 업데이트하여 JOIN
를 통해 관리자 이름을 조회합니다.
먼저 NorthwindWithSprocs
폴더에서 ~/App_Code/DAL
DataSet을 엽니다. 디자이너를 마우스 오른쪽 단추로 클릭하고 상황에 맞는 메뉴에서 추가 옵션을 선택하고 TableAdapter 메뉴 항목을 선택합니다. 그러면 TableAdapter 구성 마법사가 시작됩니다. 그림 5와 같이 마법사에서 새 저장 프로시저를 만들고 다음을 클릭합니다. TableAdapter 마법사에서 새 저장 프로시저를 만드는 방법에 대한 리프레셔를 위해 Typed DataSet의 TableAdapter에 대한 새 저장 프로시저 만들기 자습서를 참조하세요.
그림 5: 새 저장 프로시저 만들기 옵션 선택(전체 크기 이미지를 보려면 클릭)
TableAdapter의 기본 쿼리에 다음 SELECT
문을 사용합니다.
SELECT EmployeeID, LastName, FirstName, Title, HireDate, ReportsTo, Country
FROM Employees
이 쿼리에는 JOIN
이 포함되지 않으므로, TableAdapter 마법사는 기본 쿼리를 실행하기 위한 저장 프로시저뿐만 아니라 해당 INSERT
, UPDATE
, DELETE
문을 포함하여 저장 프로시저를 자동으로 생성합니다.
다음 단계에서는 TableAdapter의 저장 프로시저 이름을 지정합니다. 그림 6과 같이 이름Employees_Select
Employees_Insert
, Employees_Update
및 Employees_Delete
이름을 사용합니다.
그림 6: TableAdapter 저장 프로시저 이름 지정(전체 크기 이미지를 보려면 클릭)
마지막 단계에서는 TableAdapter 메서드의 이름을 지정하라는 메시지를 표시합니다.
Fill
및 GetEmployees
를 메서드 이름으로 사용하십시오. 또한 데이터베이스에 직접 업데이트를 보내도록 메서드 만들기(GenerateDBDirectMethods) 확인란을 선택해야 합니다.
그림 7: TableAdapter의 메서드 Fill
이름을 지정하고 GetEmployees
(전체 크기 이미지를 보려면 클릭)
마법사를 완료한 후 잠시 시간을 내어 데이터베이스의 저장 프로시저를 검사합니다. 다음 네 개의 새 항목을 확인하세요: Employees_Select
, Employees_Insert
, Employees_Update
, 그리고 Employees_Delete
. 다음으로, EmployeesDataTable
및 EmployeesTableAdapter
방금 만든 항목을 검사합니다. DataTable에는 기본 쿼리에서 반환된 각 필드에 대한 열이 포함됩니다. TableAdapter를 클릭한 다음 속성 창으로 이동합니다. 그러면 해당 저장 프로시저를 InsertCommand
호출하도록 , UpdateCommand
및 DeleteCommand
속성이 올바르게 구성된 것을 볼 수 있습니다.
그림 8: TableAdapter에 삽입, 업데이트 및 삭제 기능이 포함되어 있습니다(전체 크기 이미지를 보려면 클릭).
삽입, 업데이트 및 삭제 저장 프로시저가 자동으로 생성되고 InsertCommand
, UpdateCommand
및 DeleteCommand
속성이 올바르게 구성되면 각 직원 관리자에 대한 추가 정보를 반환하도록 저장 프로시저를 사용자 지정할 SelectCommand
준비가 된 것입니다. 특히 Employees_Select
을(를) 사용하도록 저장 프로시저를 업데이트하고 관리자 JOIN
및 FirstName
값을 반환해야 합니다. 저장 프로시저가 업데이트된 후에는 이러한 추가 열을 포함하도록 DataTable을 업데이트해야 합니다. 2단계와 3단계에서 이 두 가지 작업을 살펴보겠습니다.
2단계: 다음을 포함하도록 저장 프로시저 사용자 지정JOIN
먼저 서버 탐색기로 이동하여 Northwind 데이터베이스의 저장 프로시저 폴더로 드릴다운하고 저장 프로시저를 Employees_Select
엽니다. 이 저장 프로시저가 표시되지 않으면 저장 프로시저 폴더를 마우스 오른쪽 단추로 클릭하고 새로 고침을 선택합니다. 관리자의 이름과 성을 반환하는 데 사용할 LEFT JOIN
수 있도록 저장 프로시저를 업데이트합니다.
SELECT Employees.EmployeeID, Employees.LastName,
Employees.FirstName, Employees.Title,
Employees.HireDate, Employees.ReportsTo,
Employees.Country,
Manager.FirstName as ManagerFirstName,
Manager.LastName as ManagerLastName
FROM Employees
LEFT JOIN Employees AS Manager ON
Employees.ReportsTo = Manager.EmployeeID
문을 업데이트한 SELECT
후 파일 메뉴로 이동하여 저장을 선택하여 변경 내용을 저장 Employees_Select
합니다. 또는 도구 모음에서 저장 아이콘을 클릭하거나 Ctrl+S를 누를 수 있습니다. 변경 내용을 저장한 후 서버 탐색기에서 저장 프로시저를 마우스 오른쪽 단추로 클릭하고 Employees_Select
실행을 선택합니다. 그러면 저장 프로시저가 실행되고 출력 창에 결과가 표시됩니다(그림 9 참조).
그림 9: 저장 프로시저 결과가 출력 창에 표시됩니다(전체 크기 이미지를 보려면 클릭).
3단계: DataTable의 열 업데이트
이 시점에서 저장 프로시저는 Employees_Select
및 ManagerFirstName
값을 반환하지만, ManagerLastName
에는 이러한 열이 없습니다. 이러한 누락된 열은 다음 두 가지 방법 중 하나로 DataTable에 추가할 수 있습니다.
- 수동으로 - 데이터 세트 디자이너에서 DataTable을 마우스 오른쪽 단추로 클릭하고 추가 메뉴에서 열을 선택합니다. 그런 다음 열의 이름을 지정하고 그에 따라 해당 속성을 설정할 수 있습니다.
-
자동으로 - TableAdapter 구성 마법사는 저장 프로시저에서 반환된
SelectCommand
필드를 반영하도록 DataTable 열을 업데이트합니다. 임시 SQL 문을 사용하는 경우 마법사는InsertCommand
에UpdateCommand
가 포함됨에 따라DeleteCommand
,SelectCommand
, 및JOIN
속성도 제거합니다. 그러나 저장 프로시저를 사용하는 경우 이러한 명령 속성은 그대로 유지됩니다.
이전 자습서에서는 마스터 레코드의 글머리 기호 목록을 사용한 마스터/세부 사항 데이터 목록 및 파일 업로드를 포함하여 DataTable 열을 수동으로 추가하는 방법을 탐구했습니다. 다음 자습서에서는 이 과정을 더 자세히 살펴보겠습니다. 그러나 이 자습서에서는 TableAdapter 구성 마법사를 통해 자동 접근 방식을 사용하겠습니다.
먼저 EmployeesTableAdapter
를 마우스 오른쪽 단추로 클릭하고 상황에 맞는 메뉴에서 "구성"을 선택합니다. 그러면 TableAdapter 구성 마법사가 표시됩니다. 이 마법사는 반환 값 및 매개 변수(있는 경우)와 함께 선택, 삽입, 업데이트 및 삭제에 사용되는 저장 프로시저를 나열합니다. 그림 10은 이 마법사를 보여줍니다. 여기서 우리는 저장 프로시저가 이제 Employees_Select
및 ManagerFirstName
필드를 반환하는 것을 볼 수 있습니다.
그림 10: 저장 프로시저에 대한 Employees_Select
업데이트된 열 목록을 보여 줍니다(전체 크기 이미지를 보려면 클릭).
마침을 클릭하여 마법사를 완료합니다. 데이터 세트 디자이너 EmployeesDataTable
로 돌아가면 두 개의 추가 열, ManagerFirstName
및 ManagerLastName
이 포함됩니다.
그림 11: EmployeesDataTable
두 개의 새 열 포함(전체 크기 이미지를 보려면 클릭)
업데이트 Employees_Select
된 저장 프로시저가 적용되고 TableAdapter의 삽입, 업데이트 및 삭제 기능이 여전히 작동한다는 것을 설명하기 위해 사용자가 직원을 보고 삭제할 수 있는 웹 페이지를 만들어 보겠습니다. 그러나 이러한 페이지를 만들기 전에 먼저 DataSet의 직원과 함께 작업하기 위해 비즈니스 논리 계층에 새 클래스를 NorthwindWithSprocs
만들어야 합니다. 4단계에서는 클래스를 만듭니다 EmployeesBLLWithSprocs
. 5단계에서는 ASP.NET 페이지에서 이 클래스를 사용합니다.
4단계: 비즈니스 논리 계층 구현
라는 폴더에 ~/App_Code/BLL
새 클래스 파일을 만듭니다 EmployeesBLLWithSprocs.vb
. 이 클래스는 기존 EmployeesBLL
클래스의 의미 체계를 모방합니다. 이 새로운 클래스는 더 적은 메서드를 제공하고 NorthwindWithSprocs
DataSet을 사용하며 Northwind
DataSet 대신 사용합니다. 클래스에 다음 코드를 추가합니다 EmployeesBLLWithSprocs
.
Imports NorthwindWithSprocsTableAdapters
<System.ComponentModel.DataObject()> _
Public Class EmployeesBLLWithSprocs
Private _employeesAdapter As EmployeesTableAdapter = Nothing
Protected ReadOnly Property Adapter() As EmployeesTableAdapter
Get
If _employeesAdapter Is Nothing Then
_employeesAdapter = New EmployeesTableAdapter()
End If
Return _employeesAdapter
End Get
End Property
<System.ComponentModel.DataObjectMethodAttribute _
(System.ComponentModel.DataObjectMethodType.Select, True)> _
Public Function GetEmployees() As NorthwindWithSprocs.EmployeesDataTable
Return Adapter.GetEmployees()
End Function
<System.ComponentModel.DataObjectMethodAttribute _
(System.ComponentModel.DataObjectMethodType.Delete, True)> _
Public Function DeleteEmployee(ByVal employeeID As Integer) As Boolean
Dim rowsAffected = Adapter.Delete(employeeID)
'Return true if precisely one row was deleted, otherwise false
Return rowsAffected = 1
End Function
End Class
클래스 EmployeesBLLWithSprocs
의 속성 Adapter
은 NorthwindWithSprocs
DataSet의 인스턴스를 EmployeesTableAdapter
반환합니다. 클래스 s와 GetEmployees
및 DeleteEmployee
메서드에서 사용됩니다.
GetEmployees
메서드는 해당 EmployeesTableAdapter
메서드를 호출하여 GetEmployees
저장 프로시저를 실행하고 그 결과를 Employees_Select
에 채웁니다.
DeleteEmployee
메서드는 EmployeesTableAdapter
s Delete
메서드를 호출하며, 이는 Employees_Delete
저장 프로시저를 호출합니다.
5단계: 프레젠테이션 계층의 데이터 작업
수업이 EmployeesBLLWithSprocs
완료되면 ASP.NET 페이지를 통해 직원 데이터로 작업할 준비가 된 것입니다. 폴더에서 JOINs.aspx
AdvancedDAL
페이지를 열고 도구 상자에서 디자이너로 GridView를 끌어 속성을 ID
Employees
로 설정합니다. 다음으로 GridView의 스마트 태그에서 그리드를 새 ObjectDataSource 컨트롤에 EmployeesDataSource
바인딩합니다.
ObjectDataSource를 EmployeesBLLWithSprocs
클래스를 사용하도록 구성하고, SELECT 및 DELETE 탭에서 드롭다운 목록에서 GetEmployees
및 DeleteEmployee
메서드를 선택했는지 확인합니다. 완료를 클릭하여 ObjectDataSource의 구성을 완료합니다.
그림 12: 클래스를 사용하도록 EmployeesBLLWithSprocs
ObjectDataSource 구성(전체 크기 이미지를 보려면 클릭)
그림 13: ObjectDataSource 사용 GetEmployees
및 DeleteEmployee
메서드 사용(전체 크기 이미지를 보려면 클릭)
Visual Studio는 EmployeesDataTable
의 열마다 GridView에 BoundField를 추가합니다. 다음의 Title
, LastName
, FirstName
, ManagerFirstName
, ManagerLastName
를 제외한 모든 BoundFields를 제거합니다. 마지막 4개의 BoundFields에 대한 HeaderText
속성의 이름을 각각 성, 이름, 관리자 이름, 그리고 관리자의 성으로 바꿉니다.
사용자가 이 페이지에서 직원을 삭제할 수 있도록 하려면 두 가지 작업을 수행해야 합니다. 먼저 스마트 태그에서 삭제 사용 옵션을 확인하여 삭제 기능을 제공하도록 GridView에 지시합니다. 둘째, ObjectDataSource 마법사()에서 설정한 값에서 ObjectDataSource의 OldValuesParameterFormatString
속성을 기본값(original_{0}
{0}
)으로 변경합니다. 이러한 변경을 수행한 후 GridView 및 ObjectDataSource의 선언적 태그는 다음과 유사하게 표시됩니다.
<asp:GridView ID="Employees" runat="server" AutoGenerateColumns="False"
DataKeyNames="EmployeeID" DataSourceID="EmployeesDataSource">
<Columns>
<asp:CommandField ShowDeleteButton="True" />
<asp:BoundField DataField="Title"
HeaderText="Title"
SortExpression="Title" />
<asp:BoundField DataField="LastName"
HeaderText="Last Name"
SortExpression="LastName" />
<asp:BoundField DataField="FirstName"
HeaderText="First Name"
SortExpression="FirstName" />
<asp:BoundField DataField="ManagerFirstName"
HeaderText="Manager's First Name"
SortExpression="ManagerFirstName" />
<asp:BoundField DataField="ManagerLastName"
HeaderText="Manager's Last Name"
SortExpression="ManagerLastName" />
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="EmployeesDataSource" runat="server"
DeleteMethod="DeleteEmployee" OldValuesParameterFormatString="{0}"
SelectMethod="GetEmployees" TypeName="EmployeesBLLWithSprocs">
<DeleteParameters>
<asp:Parameter Name="employeeID" Type="Int32" />
</DeleteParameters>
</asp:ObjectDataSource>
브라우저를 통해 페이지를 방문하여 테스트합니다. 그림 14와 같이 페이지에는 각 직원과 관리자 이름이 나열됩니다(해당 직원이 있다고 가정).
그림 14: JOIN
저장 프로시저에서 Employees_Select
관리자 이름을 반환합니다(전체 크기 이미지를 보려면 클릭).
삭제 단추를 클릭하면 삭제 워크플로가 시작되며 저장 프로시저가 실행됩니다 Employees_Delete
. 그러나 외래 키 제약 조건 위반으로 인해 저장 프로시저에서 시도한 DELETE
문이 실패합니다(그림 15 참조). 특히 각 직원은 Orders
테이블에 하나 이상의 레코드를 가지고 있어 삭제에 실패합니다.
그림 15: 해당 주문이 있는 직원을 삭제하면 외래 키 제약 조건 위반이 발생합니다(전체 크기 이미지를 보려면 클릭).
직원을 삭제할 수 있도록 허용하려면 다음을 수행할 수 있습니다.
- 외래 키 제약 조건을 연쇄 삭제로 업데이트합니다.
- 삭제하려는 직원의 레코드를
Orders
테이블에서 수동으로 삭제하거나 - 저장 프로시저
Employees_Delete
를 업데이트하여,Orders
레코드를 삭제하기 전에Employees
테이블에서 관련 레코드를 먼저 삭제하십시오. Typed DataSet의 TableAdapters에 대한 기존 저장 프로시저 사용 자습서에서 이 기술을 설명했습니다.
이것을 독자가 풀어볼 연습문제로 남기겠습니다.
요약
관계형 데이터베이스를 사용하는 경우 쿼리가 여러 관련 테이블에서 데이터를 끌어오는 것이 일반적입니다. 상호 관련된 하위 쿼리 및 JOIN
s는 쿼리의 관련 테이블에서 데이터에 액세스하기 위한 두 가지 기술을 제공합니다. 이전 자습서에서는 TableAdapter가 INSERT
가 포함된 쿼리에 대해 UPDATE
, DELETE
, 및 JOIN
문을 자동으로 생성할 수 없기 때문에 상호 연관된 하위 쿼리를 가장 일반적으로 사용했습니다. 이러한 값을 수동으로 제공할 수 있지만 임시 SQL 문을 사용하는 경우 TableAdapter 구성 마법사가 완료되면 사용자 지정을 덮어씁니다.
다행히 저장 프로시저를 사용하여 만든 TableAdapters는 임시 SQL 문을 사용하여 만든 것과 동일한 취약성을 겪지 않습니다. 따라서 저장 프로시저를 사용할 때 기본 쿼리에 JOIN
를 사용하는 TableAdapter를 만드는 것이 가능합니다. 이 자습서에서는 이러한 TableAdapter를 만드는 방법을 알아보았습니다. 먼저 TableAdapter의 기본 쿼리에서 JOIN
를 포함하지 않는 SELECT
쿼리를 사용하여, 해당 삽입, 업데이트 및 삭제 저장 프로시저가 자동으로 생성되도록 했습니다. TableAdapter의 초기 구성이 완료되면, 우리는 SelectCommand
을 이용하여 저장 프로시저를 보강하고 JOIN
TableAdapter 구성 마법사를 다시 실행하여 EmployeesDataTable
의 열을 업데이트했습니다.
TableAdapter 구성 마법사를 다시 실행하면 EmployeesDataTable
저장 프로시저가 반환하는 데이터 필드를 반영하도록 Employees_Select
열이 자동으로 업데이트됩니다. 또는 이러한 열을 DataTable에 수동으로 추가할 수 있습니다. 다음 자습서에서는 DataTable에 열을 수동으로 추가하는 방법을 살펴보겠습니다.
행복한 프로그래밍!
작성자 정보
7개의 ASP/ASP.NET 책의 저자이자 4GuysFromRolla.com 창립자인 Scott Mitchell은 1998년부터 Microsoft 웹 기술을 연구해 왔습니다. Scott은 독립 컨설턴트, 트레이너 및 작가로 일합니다. 그의 최신 책은 Sams Teach Yourself ASP.NET 2.0 in 24 Hours입니다. 그에게 mitchell@4GuysFromRolla.com으로 연락할 수 있습니다.
특별히 감사드립니다.
이 자습서 시리즈는 많은 유용한 검토자가 검토했습니다. 이 자습서의 수석 검토자는 힐튼 가이세나우, 데이비드 수루, 테레사 머피였습니다. 예정된 MSDN 문서를 검토하는 데 관심이 있으신가요? 그렇다면 mitchell@4GuysFromRolla.com으로 메시지를 보내 주세요.