계산 열 작업(VB)Working with Computed Columns (VB)

Scott Mitchellby Scott Mitchell

코드 다운로드 또는 PDF 다운로드Download Code or Download PDF

데이터베이스 테이블을 만들 때 Microsoft SQL Server은 일반적으로 동일한 데이터베이스 레코드의 다른 값을 참조 하는 식에서 계산 된 값을 갖는 계산 열을 정의할 수 있습니다.When creating a database table, Microsoft SQL Server allows you to define a computed column whose value is calculated from an expression that usually references other values in the same database record. 이러한 값은 데이터베이스에서 읽기 전용 이며 Tableadapter를 사용할 때 특별 한 고려 사항이 필요 합니다.Such values are read-only at the database, which requires special considerations when working with TableAdapters. 이 자습서에서는 계산 열에서 발생 하는 문제를 충족 하는 방법을 알아봅니다.In this tutorial we learn how to meet the challenges posed by computed columns.

소개Introduction

Microsoft SQL Server은 일반적으로 동일한 테이블에 있는 다른 열의 값을 참조 하는 식에서 계산 된 값을 갖는 열인 계산 열 을 허용 합니다.Microsoft SQL Server allows for computed columns, which are columns whose values are calculated from an expression that usually references the values from other columns in the same table. 예를 들어 시간 추적 데이터 모델에는 ServicePerformed, EmployeeID, Rate, Duration등의 열이 있는 ServiceLog 라는 테이블이 있을 수 있습니다.As an example, a time tracking data model might have a table named ServiceLog with columns including ServicePerformed, EmployeeID, Rate, and Duration, among others. 웹 페이지나 기타 프로그래밍 인터페이스를 통해 서비스 항목 (요금에 대 한 요금을 곱한 금액)에 따른 금액을 계산할 수 있지만이 정보를 보고 하는 AmountDue 라는 ServiceLog 테이블에 열을 포함 하는 것이 편리할 수 있습니다.While the amount due per service item (being the rate multiplied by the duration) could be calculated through a web page or other programmatic interface, it might be handy to include a column in the ServiceLog table named AmountDue that reported this information. 이 열은 일반 열로 만들 수 있지만 Rate 또는 Duration 열 값이 변경 될 때마다 업데이트 해야 합니다.This column could be created as a normal column, but it would need to be updated anytime the Rate or Duration column values changed. Rate * Duration를 사용 하 여 AmountDue 열을 계산 열로 설정 하는 것이 더 나은 방법입니다.A better approach would be to make the AmountDue column a computed column using the expression Rate * Duration. 이렇게 하면 쿼리에서 참조 될 때마다 SQL Server에서 AmountDue 열 값을 자동으로 계산 합니다.Doing so would cause SQL Server to automatically calculate the AmountDue column value whenever it was referenced in a query.

계산 열 값은 식에 의해 결정 되므로 이러한 열은 읽기 전용 이므로 INSERT 또는 UPDATE 문에서 할당 된 값을 가질 수 없습니다.Since a computed column s value is determined by an expression, such columns are read-only and therefore cannot have values assigned to them in INSERT or UPDATE statements. 그러나 계산 열이 임시 SQL 문을 사용 하는 TableAdapter에 대 한 주 쿼리의 일부인 경우 자동 생성 된 INSERTUPDATE 문에 자동으로 포함 됩니다.However, when computed columns are part of the main query for a TableAdapter that uses ad-hoc SQL statements, they are automatically included in the auto-generated INSERT and UPDATE statements. 따라서 계산 된 열에 대 한 참조를 제거 하려면 TableAdapter s INSERTUPDATE 쿼리와 InsertCommandUpdateCommand 속성을 업데이트 해야 합니다.Consequently, the TableAdapter s INSERT and UPDATE queries and InsertCommand and UpdateCommand properties must be updated to remove references to any computed columns.

임시 SQL 문을 사용 하는 TableAdapter에서 계산 열을 사용 하는 한 가지 문제는 tableadapter 구성 마법사가 완료 될 때마다 TableAdapter s INSERTUPDATE 쿼리가 자동으로 다시 생성 된다는 것입니다.One challenge of using computed columns with a TableAdapter that uses ad-hoc SQL statements is that the TableAdapter s INSERT and UPDATE queries are automatically regenerated any time the TableAdapter Configuration wizard is completed. 따라서 마법사를 다시 실행 하면 INSERT에서 수동으로 제거 된 계산 열과 UPDATE 쿼리가 다시 나타납니다.Therefore, the computed columns manually removed from the INSERT and UPDATE queries will reappear if the wizard is re-run. 저장 프로시저를 사용 하는 Tableadapter는이 brittleness를 방해 하지 않지만 3 단계에서 해결할 수 있는 고유한 것이 있습니다.Although TableAdapters that use stored procedures don t suffer from this brittleness, they do have their own quirks that we will address in Step 3.

이 자습서에서는 Northwind 데이터베이스의 Suppliers 테이블에 계산 열을 추가한 다음이 테이블과 계산 열을 사용 하는 해당 TableAdapter를 만듭니다.In this tutorial we will add a computed column to the Suppliers table in the Northwind database and then create a corresponding TableAdapter to work with this table and its computed column. Tableadapter 구성 마법사를 사용 하는 경우 사용자 지정이 손실 되지 않도록 TableAdapter에서 임시 SQL 문 대신 저장 프로시저를 사용 합니다.We will have our TableAdapter use stored procedures instead of ad-hoc SQL statements so that our customizations aren't lost when the TableAdapter Configuration wizard is used.

S를 시작 하겠습니다.Let s get started!

1 단계:Suppliers테이블에 계산 열 추가Step 1: Adding a Computed Column to theSuppliersTable

Northwind 데이터베이스에 계산 열이 없으므로 직접 추가 해야 합니다.The Northwind database does not have any computed columns so we will need to add one ourselves. 이 자습서에서는 FullContactName 라는 Suppliers 테이블에 계산 열을 추가 하 여 ContactName (ContactTitle, CompanyName) 형식의 담당자 이름, 제목 및 회사를 반환 하는 회사를 반환 합니다.For this tutorial let s add a computed column to the Suppliers table called FullContactName that returns the contact s name, title, and the company they work for in the following format: ContactName (ContactTitle, CompanyName). 이 계산 열은 공급자에 대 한 정보를 표시할 때 보고서에서 사용할 수 있습니다.This computed column might be used in reports when displaying information about suppliers.

서버 탐색기에서 Suppliers 테이블을 마우스 오른쪽 단추로 클릭 하 고 상황에 맞는 메뉴에서 테이블 정의 열기를 선택 하 여 Suppliers 테이블 정의를 엽니다.Start by opening the Suppliers table definition by right-clicking on the Suppliers table in the Server Explorer and choosing Open Table Definition from the context-menu. 그러면 테이블의 열과 해당 속성 (예: 데이터 형식, NULL s 등을 허용할지 여부 등)이 표시 됩니다.This will display the columns of the table and their properties, such as their data type, whether they allow NULL s, and so forth. 계산 열을 추가 하려면 열 이름을 테이블 정의에 입력 하 여 시작 합니다.To add a computed column, start by typing in the name of the column into the table definition. 그런 다음 속성 창 열에서 계산 열 사양 섹션 아래의 (수식) 텍스트 상자에 식을 입력 합니다 (그림 1 참조).Next, enter its expression into the (Formula) textbox under the Computed Column Specification section in the Column Properties window (see Figure 1). 계산 열의 이름을 FullContactName 하 고 다음 식을 사용 합니다.Name the computed column FullContactName and use the following expression:

ContactName + ' (' + CASE WHEN ContactTitle IS NOT NULL THEN 
    ContactTitle + ', ' ELSE '' END + CompanyName + ')'

+ 연산자를 사용 하 여 SQL에서 문자열을 연결할 수 있습니다.Note that strings can be concatenated in SQL using the + operator. 기존 프로그래밍 언어의 조건 처럼 CASE 문을 사용할 수 있습니다.The CASE statement can be used like a conditional in a traditional programming language. 위의 식에서 CASE 문은 다음과 같이 읽을 수 있습니다. ContactTitleNULL 되지 않으면 쉼표와 연결 된 ContactTitle 값을 출력 합니다. 그렇지 않으면 아무 것도 내보내지 않습니다.In the above expression the CASE statement can be read as: If ContactTitle is not NULL then output the ContactTitle value concatenated with a comma, otherwise emit nothing. CASE 문의 유용성에 대 한 자세한 내용은 SQL CASE 문의 기능을 참조 하세요.For more on the usefulness of the CASE statement, see The Power of SQL CASE Statements.

Note

여기에서 CASE 문을 사용 하는 대신 ISNULL(ContactTitle, '')를 사용할 수도 있습니다.Instead of using a CASE statement here, we could have alternatively used ISNULL(ContactTitle, ''). ISNULL(checkExpression, replacementValue) 는 NULL이 아닌 경우 checkexpression 을 반환 하 고 그렇지 않으면 replacementValue를 반환 합니다.ISNULL(checkExpression, replacementValue) returns checkExpression if it is non-NULL, otherwise it returns replacementValue. 이 인스턴스에서 ISNULL 또는 CASE는 작동 하지만 CASE 문의 유연성이 ISNULL일치 하지 않는 복잡 한 시나리오가 있습니다.While either ISNULL or CASE will work in this instance, there are more intricate scenarios where the flexibility of the CASE statement cannot be matched by ISNULL.

이 계산 열을 추가한 후 화면은 그림 1의 스크린샷 처럼 보입니다.After adding this computed column your screen should look like the screen shot in Figure 1.

FullContactName 라는 계산 열을 Suppliers 테이블에 추가 Add a Computed Column Named FullContactName to the Suppliers Table

그림 1: FullContactName 라는 계산 열을 Suppliers 테이블에 추가 (전체 크기 이미지를 보려면 클릭)Figure 1: Add a Computed Column Named FullContactName to the Suppliers Table (Click to view full-size image)

계산 열의 이름을 지정 하 고 해당 식을 입력 한 후에는 도구 모음에서 저장 아이콘을 클릭 하거나, Ctrl + S를 누르거나, 파일 메뉴로 이동 하 고 Suppliers저장을 선택 하 여 변경 내용을 테이블에 저장 합니다.After naming the computed column and entering its expression, save the changes to the table by clicking the Save icon in the toolbar, by hitting Ctrl+S, or by going to the File menu and choosing Save Suppliers.

테이블을 저장 하면 Suppliers 테이블의 열 목록에 추가 된 열을 포함 하 여 서버 탐색기를 새로 고쳐야 합니다.Saving the table should refresh the Server Explorer, including the just-added column in the Suppliers table s column list. 또한 (수식) 텍스트 상자에 입력 된 식이 불필요 한 공백을 제거 하 고 열 이름을 대괄호 ([])로 둘러싸고 괄호를 포함 하 여 작업 순서를 보다 명확 하 게 표시 하는 동등한 식으로 자동 조정 됩니다.Furthermore, the expression entered into the (Formula) textbox will automatically adjust to an equivalent expression that strips unnecessary whitespace, surrounds column names with brackets ([]), and includes parentheses to more explicitly show the order of operations:

(((([ContactName]+' (')+case when [ContactTitle] IS NOT NULL 
    then [ContactTitle]+', ' else '' end)+[CompanyName])+')')

Microsoft SQL Server 계산 열에 대 한 자세한 내용은 기술 문서를 참조 하세요.For more information on computed columns in Microsoft SQL Server, refer to the technical documentation. 또한 방법: 계산 열을 만드는 단계별 연습은 계산 열 지정을 참조 하세요.Also check out the How to: Specify Computed Columns for a step-by-step walkthrough of creating computed columns.

Note

기본적으로 계산 열은 테이블에 물리적으로 저장 되지 않고 쿼리에서 참조 될 때마다 다시 계산 됩니다.By default, computed columns are not physically stored in the table but are instead recalculated each time they are referenced in a query. 그러나 유지 됨 확인란을 선택 하면 계산 열을 테이블에 물리적으로 저장 하도록 SQL Server에 지시할 수 있습니다.By checking the Is Persisted checkbox, however, you can instruct SQL Server to physically store the computed column in the table. 이렇게 하면 계산 열에 인덱스를 만들 수 있으므로 해당 WHERE 절에서 계산 열 값을 사용 하는 쿼리의 성능을 향상 시킬 수 있습니다.Doing so allows an index to be created on the computed column, which can improve the performance of queries that use the computed column value in their WHERE clauses. 자세한 내용은 계산 열에 인덱스 만들기 를 참조 하세요.See Creating Indexes on Computed Columns for more information.

2 단계: 계산 열 값 보기Step 2: Viewing the Computed Column s Values

데이터 액세스 계층에서 작업을 시작 하기 전에 FullContactName 값을 확인 하는 데 1 분 정도 걸립니다.Before we start work on the Data Access Layer, let s take a minute to view the FullContactName values. 서버 탐색기에서 Suppliers 테이블 이름을 마우스 오른쪽 단추로 클릭 하 고 상황에 맞는 메뉴에서 새 쿼리를 선택 합니다.From the Server Explorer, right-click on the Suppliers table name and choose New Query from the context-menu. 그러면 쿼리에 포함할 테이블을 선택 하 라는 메시지를 표시 하는 쿼리 창이 표시 됩니다.This will bring up a Query window that prompts us to choose what tables to include in the query. Suppliers 테이블을 추가 하 고 닫기를 클릭 합니다.Add the Suppliers table and click Close. 그런 다음 Suppliers 테이블에서 CompanyName, ContactName, ContactTitleFullContactName 열을 확인 합니다.Next, check the CompanyName, ContactName, ContactTitle, and FullContactName columns from the Suppliers table. 마지막으로 도구 모음에서 빨간 느낌표 아이콘을 클릭 하 여 쿼리를 실행 하 고 결과를 확인 합니다.Finally, click the red exclamation point icon in the Toolbar to execute the query and view the results.

그림 2에 나와 있는 것 처럼 결과에는 ContactName (ContactTitle, CompanyName) 형식을 사용 하 여 CompanyName, ContactNameContactTitle 열을 나열 하는 FullContactName포함 되어 있습니다.As Figure 2 shows, the results include FullContactName, which lists the CompanyName, ContactName, and ContactTitle columns using the format ContactName (ContactTitle, CompanyName) .

FullContactName ContactName (ContactTitle, CompanyName) 형식을 사용 하는 The FullContactName Uses the Format ContactName (ContactTitle, CompanyName)

그림 2: ContactName 형식 (ContactTitle, CompanyName)을 사용 하 FullContactName (전체 크기 이미지를 보려면 클릭)Figure 2: The FullContactName Uses the Format ContactName (ContactTitle, CompanyName) (Click to view full-size image)

3 단계: 데이터 액세스 계층에SuppliersTableAdapter추가Step 3: Adding theSuppliersTableAdapterto the Data Access Layer

응용 프로그램에서 공급자 정보를 사용 하려면 먼저 DAL에서 TableAdapter 및 DataTable을 만들어야 합니다.In order to work with the supplier information in our application we need to first create a TableAdapter and DataTable in our DAL. 이러한 작업은 이전 자습서에서 살펴본 것과 동일한 간단한 단계를 사용 하 여 수행 하는 것이 가장 좋습니다.Ideally, this would be accomplished using the same straightforward steps examined in earlier tutorials. 그러나 계산 열을 사용 하 여 작업 하는 데는 몇 가지 사항이 있습니다.However, working with computed columns introduces a few wrinkles that merit discussion.

임시 SQL 문을 사용 하는 TableAdapter를 사용 하는 경우 tableadapter 구성 마법사를 통해 TableAdapter의 주 쿼리에 계산 열을 간단히 포함할 수 있습니다.If you are using a TableAdapter that uses ad-hoc SQL statements, you can simply include the computed column in the TableAdapter s main query via the TableAdapter Configuration wizard. 그러나 이렇게 하면 계산 열이 포함 된 INSERTUPDATE 문이 자동 생성 됩니다.This, however, will auto-generate INSERT and UPDATE statements that include the computed column. 이러한 메서드 중 하나 SqlException를 실행 하려고 하면 열 ColumnName이 계산 열 이거나 UNION 연산자의 결과가 throw 되기 때문에 열 ColumnName 을 수정할 수 없습니다.If you attempt to execute one of these methods, a SqlException with the message The column ColumnName cannot be modified because it is either a computed column or is the result of a UNION operator will be thrown. INSERTUPDATE 문은 TableAdapter의 InsertCommandUpdateCommand 속성을 통해 수동으로 조정할 수 있지만 TableAdapter 구성 마법사가 다시 실행 될 때마다 이러한 사용자 지정이 손실 됩니다.While the INSERT and UPDATE statement can be manually adjusted through the TableAdapter s InsertCommand and UpdateCommand properties, these customizations will be lost whenever the TableAdapter Configuration wizard is re-run.

임시 SQL 문을 사용 하는 Tableadapter의 brittleness 때문에 계산 열로 작업할 때 저장 프로시저를 사용 하는 것이 좋습니다.Due to the brittleness of TableAdapters that use ad-hoc SQL statements, it is recommended that we use stored procedures when working with computed columns. 기존 저장 프로시저를 사용 하는 경우 형식화 된 데이터 집합의 tableadapter 자습서에 대 한 기존 저장 프로시저 사용 의 설명에 따라 tableadapter를 구성 하면 됩니다.If you are using existing stored procedures, simply configure the TableAdapter as discussed in the Using Existing Stored Procedures for the Typed DataSet s TableAdapters tutorial. 그러나 TableAdapter 마법사에서 저장 프로시저를 만드는 경우에는 처음에 주 쿼리에서 계산 열을 생략 하는 것이 중요 합니다.If you have the TableAdapter wizard create the stored procedures for you, however, it is important to initially omit any computed columns from the main query. 주 쿼리에 계산 열을 포함 하는 경우 TableAdapter 구성 마법사가 완료 되 면 해당 저장 프로시저를 만들 수 없다는 알림을 표시 합니다.If you include a computed column in the main query, the TableAdapter Configuration wizard will inform you, upon completion, that it cannot create the corresponding stored procedures. 간단히 말해서 계산 열을 사용 하지 않는 주 쿼리를 사용 하 여 먼저 TableAdapter를 구성 하 고 해당 저장 프로시저와 TableAdapter s SelectCommand를 수동으로 업데이트 하 여 계산 열을 포함 해야 합니다.In short, we need to initially configure the TableAdapter using a computed column-free main query and then manually update the corresponding stored procedure and the TableAdapter s SelectCommand to include the computed column. 이 방법은JOINs 자습서를 사용 하기 위해 TableAdapter를 업데이트 하는 데 사용 되는 방법과 비슷합니다.This approach is similar to the one used in the Updating the TableAdapter to UseJOINs tutorial.

이 자습서에서는를 사용 하 여 새 TableAdapter를 추가 하 고 저장 프로시저를 자동으로 만듭니다.For this tutorial, let s add a new TableAdapter and have it automatically create the stored procedures for us. 따라서 처음에는 주 쿼리에서 FullContactName 계산 열을 생략 해야 합니다.Consequently, we will need to initially omit the FullContactName computed column from the main query.

먼저 ~/App_Code/DAL 폴더에서 NorthwindWithSprocs 데이터 집합을 엽니다.Start by opening the NorthwindWithSprocs DataSet in the ~/App_Code/DAL folder. 디자이너를 마우스 오른쪽 단추로 클릭 하 고 상황에 맞는 메뉴에서 새 TableAdapter를 추가 하도록 선택 합니다.Right-click in the Designer and, from the context-menu, choose to add a new TableAdapter. 이렇게 하면 TableAdapter 구성 마법사가 시작 됩니다.This will launch the TableAdapter Configuration wizard. 데이터를 쿼리할 데이터베이스 (NORTHWNDConnectionString Web.config)를 지정 하 고 다음을 클릭 합니다.Specify the database to query data from (NORTHWNDConnectionString from Web.config) and click Next. Suppliers 테이블을 쿼리 하거나 수정 하기 위한 저장 프로시저를 아직 만들지 않았기 때문에 새 저장 프로시저 만들기 옵션을 선택 하 여 마법사에서 해당 테이블을 만들고 다음을 클릭 합니다.Since we have not yet created any stored procedures for querying or modifying the Suppliers table, select the Create new stored procedures option so that the wizard will create them for us and click Next.

새 저장 프로시저 만들기 옵션을 선택 합니다.Choose the Create new stored procedures Option

그림 3: 새 저장 프로시저 만들기 옵션 선택 (전체 크기 이미지를 보려면 클릭)Figure 3: Choose the Create new stored procedures Option (Click to view full-size image)

이후 단계에서 주 쿼리를 묻는 메시지를 표시 합니다.The subsequent step prompts us for the main query. 각 공급자에 대 한 SupplierID, CompanyName, ContactNameContactTitle 열을 반환 하는 다음 쿼리를 입력 합니다.Enter the following query, which returns the SupplierID, CompanyName, ContactName, and ContactTitle columns for each supplier. 이 쿼리는 계산 열 (FullContactName)을 의도적으로 생략 합니다. 4 단계에서이 열을 포함 하도록 해당 저장 프로시저를 업데이트 합니다.Note that this query purposefully omits the computed column (FullContactName); we will update the corresponding stored procedure to include this column in Step 4.

SELECT SupplierID, CompanyName, ContactName, ContactTitle
FROM Suppliers

주 쿼리를 입력 하 고 다음을 클릭 하면 마법사에서 생성 되는 네 개의 저장 프로시저 이름을 지정할 수 있습니다.After entering the main query and clicking Next, the wizard allows us to name the four stored procedures it will generate. 그림 4에서 보여 주는 것 처럼 이러한 저장 프로시저 Suppliers_Select, Suppliers_Insert, Suppliers_UpdateSuppliers_Delete의 이름을로 합니다.Name these stored procedures Suppliers_Select, Suppliers_Insert, Suppliers_Update, and Suppliers_Delete, as Figure 4 illustrates.

자동 생성 된 저장 프로시저의 이름을 사용자 지정 Customize the Names of the Auto-Generated Stored Procedures

그림 4: 자동 생성 된 저장 프로시저의 이름 사용자 지정 (전체 크기 이미지를 보려면 클릭)Figure 4: Customize the Names of the Auto-Generated Stored Procedures (Click to view full-size image)

다음 마법사 단계에서는 TableAdapter의 메서드 이름을 지정 하 고 데이터에 액세스 하 고 업데이트 하는 데 사용 되는 패턴을 지정할 수 있습니다.The next wizard step allows us to name the TableAdapter s methods and specify the patterns used to access and update data. 세 개의 확인란을 모두 선택 된 상태로 두고 GetData 메서드의 이름을 GetSuppliers로 바꿉니다.Leave all three checkboxes checked, but rename the GetData method to GetSuppliers. 마침을 클릭하여 마법사를 완료합니다.Click Finish to complete the wizard.

GetData 메서드를 GetSuppliers로 이름 바꾸기 Rename the GetData Method to GetSuppliers

그림 5: GetData 메서드의 이름을 GetSuppliers (전체 크기 이미지를 보려면 클릭)Figure 5: Rename the GetData Method to GetSuppliers (Click to view full-size image)

마침을 클릭 하면 마법사가 4 개의 저장 프로시저를 만들고 TableAdapter 및 해당 DataTable을 형식화 된 데이터 집합에 추가 합니다.Upon clicking Finish, the wizard will create the four stored procedures and add the TableAdapter and corresponding DataTable to the Typed DataSet.

4 단계: TableAdapter 주 쿼리에 계산 열 포함Step 4: Including the Computed Column in the TableAdapter s Main Query

이제 FullContactName 계산 열을 포함 하도록 3 단계에서 만든 TableAdapter 및 DataTable을 업데이트 해야 합니다.We now need to update the TableAdapter and DataTable created in Step 3 to include the FullContactName computed column. 여기에는 다음 두 단계가 포함됩니다.This involves two steps:

  1. Suppliers_Select 저장 프로시저를 업데이트 하 여 FullContactName 계산 열을 반환 합니다.Updating the Suppliers_Select stored procedure to return the FullContactName computed column, and
  2. 해당 FullContactName 열을 포함 하도록 DataTable을 업데이트 합니다.Updating the DataTable to include a corresponding FullContactName column.

먼저 서버 탐색기로 이동 하 여 저장 프로시저 폴더로 드릴 다운 합니다.Start by navigating to the Server Explorer and drilling down into the Stored Procedures folder. Suppliers_Select 저장 프로시저를 열고 FullContactName 계산 열을 포함 하도록 SELECT 쿼리를 업데이트 합니다.Open the Suppliers_Select stored procedure and update the SELECT query to include the FullContactName computed column:

SELECT SupplierID, CompanyName, ContactName, ContactTitle, FullContactName
FROM Suppliers

도구 모음에서 저장 아이콘을 클릭 하거나, Ctrl + S를 누르거나, 파일 메뉴에서 Suppliers_Select 저장 옵션을 선택 하 여 저장 프로시저에 대 한 변경 내용을 저장 합니다.Save the changes to the stored procedure by clicking the Save icon in the Toolbar, by hitting Ctrl+S, or by choosing the Save Suppliers_Select option from the File menu.

그런 다음 데이터 집합 디자이너로 돌아가서 SuppliersTableAdapter를 마우스 오른쪽 단추로 클릭 하 고 상황에 맞는 메뉴에서 구성을 선택 합니다.Next, return to the DataSet Designer, right-click on the SuppliersTableAdapter, and choose Configure from the context-menu. 이제 Suppliers_Select 열에는 데이터 열 컬렉션에 FullContactName 열이 포함 됩니다.Note that the Suppliers_Select column now includes the FullContactName column in its Data Columns collection.

TableAdapter s 구성 마법사를 실행 하 여 DataTable의 열을 업데이트 Run the TableAdapter s Configuration Wizard to Update the DataTable s Columns

그림 6: TableAdapter s 구성 마법사를 실행 하 여 DataTable s 열 업데이트 (전체 크기 이미지를 보려면 클릭)Figure 6: Run the TableAdapter s Configuration Wizard to Update the DataTable s Columns (Click to view full-size image)

마침을 클릭하여 마법사를 완료합니다.Click Finish to complete the wizard. 그러면 SuppliersDataTable에 해당 열이 자동으로 추가 됩니다.This will automatically add a corresponding column to the SuppliersDataTable. TableAdapter 마법사는 FullContactName 열이 계산 열 이므로 읽기 전용 임을 감지할 수 있을 정도로 지능적입니다.The TableAdapter wizard is smart enough to detect that the FullContactName column is a computed column and therefore read-only. 따라서 열 s ReadOnly 속성을 true로 설정 합니다.Consequently, it sets the column s ReadOnly property to true. 이를 확인 하려면 SuppliersDataTable에서 열을 선택한 다음 속성 창으로 이동 합니다 (그림 7 참조).To verify this, select the column from the SuppliersDataTable and then go to the Properties window (see Figure 7). FullContactName 열 s DataTypeMaxLength 속성도 그에 따라 설정 됩니다.Note that the FullContactName column s DataType and MaxLength properties are also set accordingly.

FullContactName 열이 읽기 전용으로 표시 The FullContactName Column is Marked as Read-Only

그림 7: FullContactName 열이 읽기 전용으로 표시 되어 있습니다 (전체 크기 이미지를 보려면 클릭).Figure 7: The FullContactName Column is Marked as Read-Only (Click to view full-size image)

5 단계: TableAdapter에GetSupplierBySupplierID메서드 추가Step 5: Adding aGetSupplierBySupplierIDMethod to the TableAdapter

이 자습서에서는 업데이트 가능한 표에 공급 업체를 표시 하는 ASP.NET 페이지를 만듭니다.For this tutorial we will create an ASP.NET page that displays the suppliers in an updateable grid. 이전 자습서에서는 DAL에서 특정 레코드를 강력한 형식의 DataTable로 검색 하 고 해당 속성을 업데이트 한 다음 업데이트 된 DataTable을 다시 DAL으로 전송 하 여 변경 내용을에 전파 함으로써 비즈니스 논리 계층에서 단일 레코드를 업데이트 했습니다. 데이터베이스입니다.In past tutorials we have updated a single record from the Business Logic Layer by retrieving that particular record from the DAL as a strongly-typed DataTable, updating its properties, and then sending the updated DataTable back to the DAL to propagate the changes to the database. 이 첫 번째 단계를 수행 하려면 DAL에서 업데이트 되는 레코드를 검색 합니다. 먼저 GetSupplierBySupplierID(supplierID) 메서드를 DAL에 추가 해야 합니다.To accomplish this first step - retrieving the record being updated from the DAL - we need to first add a GetSupplierBySupplierID(supplierID) method to the DAL.

데이터 집합 디자인에서 SuppliersTableAdapter를 마우스 오른쪽 단추로 클릭 하 고 상황에 맞는 메뉴에서 쿼리 추가 옵션을 선택 합니다.Right-click on the SuppliersTableAdapter in the DataSet Design and choose the Add Query option from the context-menu. 3 단계에서와 같이 새 저장 프로시저 만들기 옵션을 선택 하 여 마법사에서 새 저장 프로시저를 생성 하도록 합니다 (이 마법사의 스크린샷에 대해서는 그림 3 참조).As we did in Step 3, let the wizard generate a new stored procedure for us by selecting the Create new stored procedure option (refer back to Figure 3 for a screenshot of this wizard step). 이 메서드는 여러 열이 있는 레코드를 반환 하므로 행을 반환 하는 SELECT 인 SQL 쿼리를 사용 하 고 다음을 클릭 함을 표시 합니다.Since this method will return a record with multiple columns, indicate that we want to use a SQL query that is a SELECT which returns rows and click Next.

행을 반환 하는 옵션을 선택 합니다.Choose the SELECT which returns rows Option

그림 8: 행을 반환 하는 값 선택 옵션 선택 (전체 크기 이미지를 보려면 클릭)Figure 8: Choose the SELECT which returns rows Option (Click to view full-size image)

후속 단계에서는이 메서드에 사용할 쿼리를 묻는 메시지를 표시 합니다.The subsequent step prompts us for the query to use for this method. 주 쿼리와 동일한 데이터 필드를 반환 하지만 특정 공급자에 대해 다음을 입력 합니다.Enter the following, which returns the same data fields as the main query but for a particular supplier.

SELECT SupplierID, CompanyName, ContactName, ContactTitle, FullContactName
FROM Suppliers
WHERE SupplierID = @SupplierID

다음 화면은 자동 생성 될 저장 프로시저의 이름을 묻는 메시지를 표시 합니다.The next screen asks us to name the stored procedure that will be auto-generated. 이 저장 프로시저의 이름을 Suppliers_SelectBySupplierID 하 고 다음을 클릭 합니다.Name this stored procedure Suppliers_SelectBySupplierID and click Next.

저장 프로시저의 이름을 Suppliers_SelectBySupplierIDName the Stored Procedure Suppliers_SelectBySupplierID

그림 9: 저장 프로시저의 이름 Suppliers_SelectBySupplierID (전체 크기 이미지를 보려면 클릭)Figure 9: Name the Stored Procedure Suppliers_SelectBySupplierID (Click to view full-size image)

마지막으로, 마법사에서 TableAdapter에 사용할 데이터 액세스 패턴 및 메서드 이름을 묻는 메시지를 표시 합니다.Lastly, the wizard prompts us for the data access patterns and method names to use for the TableAdapter. 두 확인란을 모두 선택 된 상태로 두고 FillByGetDataBy 메서드의 이름을 각각 FillBySupplierIDGetSupplierBySupplierID로 바꿉니다.Leave both checkboxes checked, but rename the FillBy and GetDataBy methods to FillBySupplierID and GetSupplierBySupplierID, respectively.

TableAdapter 메서드의 FillBySupplierID 및 GetSupplierBySupplierID 이름Name the TableAdapter Methods FillBySupplierID and GetSupplierBySupplierID

그림 10: TableAdapter 메서드 이름 FillBySupplierIDGetSupplierBySupplierID (전체 크기 이미지를 보려면 클릭)Figure 10: Name the TableAdapter Methods FillBySupplierID and GetSupplierBySupplierID (Click to view full-size image)

마침을 클릭하여 마법사를 완료합니다.Click Finish to complete the wizard.

6 단계: 비즈니스 논리 계층 만들기Step 6: Creating the Business Logic Layer

1 단계에서 만든 계산 열을 사용 하는 ASP.NET 페이지를 만들기 전에 먼저 BLL에 해당 메서드를 추가 해야 합니다.Before we create an ASP.NET page that uses the computed column created in Step 1, we first need to add the corresponding methods in the BLL. 7 단계에서 만든 ASP.NET 페이지를 통해 사용자는 공급자를 보고 편집할 수 있습니다.Our ASP.NET page, which we will create in Step 7, will allow users to view and edit suppliers. 따라서 항상 모든 공급 업체를 가져오는 메서드를 제공 하 고 특정 공급자를 업데이트 하는 메서드를 제공 해야 합니다.Therefore, we need our BLL to provide, at minimum, a method to get all of the suppliers and another to update a particular supplier.

~/App_Code/BLL 폴더에 SuppliersBLLWithSprocs 라는 새 클래스 파일을 만들고 다음 코드를 추가 합니다.Create a new class file named SuppliersBLLWithSprocs in the ~/App_Code/BLL folder and add the following code:

Imports NorthwindWithSprocsTableAdapters
<System.ComponentModel.DataObject()> _
Public Class SuppliersBLLWithSprocs
    Private _suppliersAdapter As SuppliersTableAdapter = Nothing
    Protected ReadOnly Property Adapter() As SuppliersTableAdapter
        Get
            If _suppliersAdapter Is Nothing Then
                _suppliersAdapter = New SuppliersTableAdapter()
            End If
            Return _suppliersAdapter
        End Get
    End Property
    <System.ComponentModel.DataObjectMethodAttribute _
        (System.ComponentModel.DataObjectMethodType.Select, True)> _
    Public Function GetSuppliers() As NorthwindWithSprocs.SuppliersDataTable
        Return Adapter.GetSuppliers()
    End Function
    <System.ComponentModel.DataObjectMethodAttribute _
        (System.ComponentModel.DataObjectMethodType.Update, True)> _
    Public Function UpdateSupplier(companyName As String, contactName As String, _
        contactTitle As String, supplierID As Integer) As Boolean
        Dim suppliers As NorthwindWithSprocs.SuppliersDataTable = _
            Adapter.GetSupplierBySupplierID(supplierID)
        If suppliers.Count = 0 Then
            ' no matching record found, return false
            Return False
        End If
        Dim supplier As NorthwindWithSprocs.SuppliersRow = suppliers(0)
        supplier.CompanyName = companyName
        If contactName Is Nothing Then 
            supplier.SetContactNameNull() 
        Else 
            supplier.ContactName = contactName
        End If
        If contactTitle Is Nothing Then 
            supplier.SetContactTitleNull() 
        Else 
            supplier.ContactTitle = contactTitle
        End If
        ' Update the product record
        Dim rowsAffected As Integer = Adapter.Update(supplier)
        ' Return true if precisely one row was updated, otherwise false
        Return rowsAffected = 1
    End Function
End Class

다른 BLL 클래스와 마찬가지로 SuppliersBLLWithSprocs에는 PublicGetSuppliers의 두 가지 UpdateSupplier메서드와 함께 SuppliersTableAdapter 클래스의 인스턴스를 반환 하는 Protected Adapter 속성이 있습니다.Like the other BLL classes, SuppliersBLLWithSprocs has a Protected Adapter property that returns an instance of the SuppliersTableAdapter class along with two Public methods: GetSuppliers and UpdateSupplier. GetSuppliers 메서드는를 호출 하 고 데이터 액세스 계층의 해당 GetSupplier 메서드에서 반환 되는 SuppliersDataTable 반환 합니다.The GetSuppliers method calls and returns the SuppliersDataTable returned by the corresponding GetSupplier method in the Data Access Layer. UpdateSupplier 메서드는 DAL s GetSupplierBySupplierID(supplierID) 메서드 호출을 통해 업데이트 되는 특정 공급자에 대 한 정보를 검색 합니다.The UpdateSupplier method retrieves information about the particular supplier being updated via a call to the DAL s GetSupplierBySupplierID(supplierID) method. 그런 다음 CategoryName, ContactNameContactTitle 속성을 업데이트 하 고, 수정 된 SuppliersRow 개체를 전달 하 여 데이터 액세스 계층 Update 메서드를 호출 하 여 이러한 변경 내용을 데이터베이스에 커밋합니다.It then updates the CategoryName, ContactName, and ContactTitle properties and commits these changes to the database by calling the Data Access Layer s Update method, passing in the modified SuppliersRow object.

Note

SupplierIDCompanyName를 제외 하 고 Suppliers 테이블의 모든 열은 NULL 값을 허용 합니다.Except for SupplierID and CompanyName, all columns in the Suppliers table allow NULL values. 따라서 전달 된 contactName 또는 contactTitle 매개 변수가 Nothing 인 경우 각각 ContactTitleNULL 메서드를 사용 하 여 해당 ContactNameSetContactNameNull 속성을 SetContactTitleNull 데이터베이스 값으로 설정 해야 합니다.Therefore, if the passed-in contactName or contactTitle parameters are Nothing we need to set the corresponding ContactName and ContactTitle properties to a NULL database value using the SetContactNameNull and SetContactTitleNull methods, respectively.

7 단계: 프레젠테이션 계층에서 계산 열 사용Step 7: Working with the Computed Column from the Presentation Layer

Suppliers 테이블에 계산 열이 추가 되 고 DAL 및 BLL이 적절히 업데이트 되 면 FullContactName 계산 열을 사용 하는 ASP.NET 페이지를 작성할 준비가 된 것입니다.With the computed column added to the Suppliers table and the DAL and BLL updated accordingly, we are ready to build an ASP.NET page that works with the FullContactName computed column. 먼저 AdvancedDAL 폴더에서 ComputedColumns.aspx 페이지를 열고 GridView를 도구 상자에서 디자이너로 끌어 옵니다.Start by opening the ComputedColumns.aspx page in the AdvancedDAL folder and drag a GridView from the Toolbox onto the Designer. GridView s ID 속성을 Suppliers로 설정 하 고 스마트 태그에서 SuppliersDataSource라는 새 ObjectDataSource에 바인딩합니다.Set the GridView s ID property to Suppliers and, from its smart tag, bind it to a new ObjectDataSource named SuppliersDataSource. 6 단계에서 다시 추가한 SuppliersBLLWithSprocs 클래스를 사용 하도록 ObjectDataSource를 구성 하 고 다음을 클릭 합니다.Configure the ObjectDataSource to use the SuppliersBLLWithSprocs class we added back in Step 6 and click Next.

SuppliersBLLWithSprocs 클래스를 사용 하도록 ObjectDataSource 구성 Configure the ObjectDataSource to Use the SuppliersBLLWithSprocs Class

그림 11: SuppliersBLLWithSprocs 클래스를 사용 하도록 ObjectDataSource 구성 (전체 크기 이미지를 보려면 클릭)Figure 11: Configure the ObjectDataSource to Use the SuppliersBLLWithSprocs Class (Click to view full-size image)

SuppliersBLLWithSprocs 클래스에는 GetSuppliersUpdateSupplier라는 두 가지 메서드만 정의 되어 있습니다.There are only two methods defined in the SuppliersBLLWithSprocs class: GetSuppliers and UpdateSupplier. 이러한 두 가지 방법이 선택 및 업데이트 탭에 각각 지정 되어 있는지 확인 하 고 마침을 클릭 하 여 ObjectDataSource의 구성을 완료 합니다.Ensure that these two methods are specified in the SELECT and UPDATE tabs, respectively, and click Finish to complete the configuration of the ObjectDataSource.

데이터 소스 구성 마법사가 완료 되 면 Visual Studio에서 반환 된 각 데이터 필드에 대해 BoundField를 추가 합니다.Upon completion of the Data Source Configuration wizard, Visual Studio will add a BoundField for each of the data fields returned. SupplierID BoundField를 제거 하 고 CompanyName, ContactName, ContactTitleFullContactName BoundFields의 HeaderText 속성을 회사, 연락처 이름, 제목 및 전체 연락처 이름으로 변경 합니다.Remove the SupplierID BoundField and change the HeaderText properties of the CompanyName, ContactName, ContactTitle, and FullContactName BoundFields to Company, Contact Name, Title, and Full Contact Name, respectively. 스마트 태그에서 편집 사용 확인란을 선택 하 여 GridView s 기본 제공 편집 기능을 설정 합니다.From the smart tag, check the Enable Editing checkbox to turn on the GridView s built-in editing capabilities.

BoundFields를 GridView에 추가 하는 것 외에도 데이터 원본 마법사가 완료 되 면 Visual Studio가 ObjectDataSource s OldValuesParameterFormatString 속성을 원래_{0}설정 합니다.In addition to adding BoundFields to the GridView, completion of the Data Source Wizard also causes Visual Studio to set the ObjectDataSource s OldValuesParameterFormatString property to original_{0}. 이 설정을 기본값으로 되돌려 {0} 합니다.Revert this setting back to its default value, {0} .

GridView와 ObjectDataSource를 편집한 후에는 해당 선언적 태그가 다음과 같이 표시 됩니다.After making these edits to the GridView and ObjectDataSource, their declarative markup should look similar to the following:

<asp:GridView ID="Suppliers" runat="server" AutoGenerateColumns="False" 
    DataKeyNames="SupplierID" DataSourceID="SuppliersDataSource">
    <Columns>
        <asp:CommandField ShowEditButton="True" />
        <asp:BoundField DataField="CompanyName" 
            HeaderText="Company" 
            SortExpression="CompanyName" />
        <asp:BoundField DataField="ContactName" 
            HeaderText="Contact Name" 
            SortExpression="ContactName" />
        <asp:BoundField DataField="ContactTitle" 
            HeaderText="Title" 
            SortExpression="ContactTitle" />
        <asp:BoundField DataField="FullContactName" 
            HeaderText="Full Contact Name"
            SortExpression="FullContactName" 
            ReadOnly="True" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="SuppliersDataSource" runat="server"
    SelectMethod="GetSuppliers" TypeName="SuppliersBLLWithSprocs" 
        UpdateMethod="UpdateSupplier">
    <UpdateParameters>
        <asp:Parameter Name="companyName" Type="String" />
        <asp:Parameter Name="contactName" Type="String" />
        <asp:Parameter Name="contactTitle" Type="String" />
        <asp:Parameter Name="supplierID" Type="Int32" />
    </UpdateParameters>
</asp:ObjectDataSource>

그런 다음 브라우저를 통해이 페이지를 방문 합니다.Next, visit this page through a browser. 그림 12와 같이 각 공급 업체는 FullContactName 열을 포함 하는 표에 나열 됩니다. 해당 값은 ContactName (ContactTitle, CompanyName)로 형식이 지정 된 다른 세 열의 연결입니다.As Figure 12 shows, each supplier is listed in a grid that includes the FullContactName column, whose value is simply the concatenation of the other three columns formatted as ContactName (ContactTitle, CompanyName) .

각 공급 업체 표에 나열 됩니다.Each Supplier is Listed in the Grid

그림 12: 각 공급자가 표에 나열 됩니다 (전체 크기 이미지를 보려면 클릭).Figure 12: Each Supplier is Listed in the Grid (Click to view full-size image)

특정 공급자에 대 한 편집 단추를 클릭 하면 다시 게시 되 고 해당 행이 편집 인터페이스에서 렌더링 됩니다 (그림 13 참조).Clicking the Edit button for a particular supplier causes a postback and has that row rendered in its editing interface (see Figure 13). 처음 세 개의 열은 기본 편집 인터페이스에서 렌더링 됩니다. 텍스트 상자 컨트롤 Text 속성은 데이터 필드의 값으로 설정 됩니다.The first three columns render in their default editing interface - a TextBox control whose Text property is set to the value of the data field. 그러나 FullContactName 열은 텍스트로 유지 됩니다.The FullContactName column, however, remains as text. 데이터 소스 구성 마법사가 완료 되 면 GridView에 BoundFields이 추가 되 면 SuppliersDataTable의 해당 FullContactName 열에 ReadOnly 속성이 True로 설정 되어 있기 때문에 FullContactName BoundField s ReadOnly 속성이 True로 설정 됩니다.When the BoundFields were added to the GridView at the completion of the Data Source Configuration wizard, the FullContactName BoundField s ReadOnly property was set to True because the corresponding FullContactName column in the SuppliersDataTable has its ReadOnly property set to True. 4 단계에서 설명한 대로 FullContactName s ReadOnly 속성은 TableAdapter에서 열이 계산 열 임을 검색 했기 때문에 True로 설정 되었습니다.As noted in Step 4, the FullContactName s ReadOnly property was set to True because the TableAdapter detected that the column was a computed column.

FullContactName 열을 편집할 수 The FullContactName Column is Not Editable

그림 13: FullContactName 열을 편집할 수 없음 (전체 크기 이미지를 보려면 클릭)Figure 13: The FullContactName Column is Not Editable (Click to view full-size image)

계속 해 서 편집 가능한 하나 이상의 열 값을 업데이트 하 고 업데이트를 클릭 합니다.Go ahead and update the value of one or more of the editable columns and click Update. FullContactName 값이 변경 내용을 반영 하도록 자동으로 업데이트 되는 방식을 확인 합니다.Note how the FullContactName s value is automatically updated to reflect the change.

Note

GridView는 현재 편집 가능한 필드에 대해 BoundFields를 사용 하 여 기본 편집 인터페이스를 생성 합니다.The GridView currently uses BoundFields for the editable fields, resulting in the default editing interface. CompanyName 필드는 필수 이므로 RequiredFieldValidator를 포함 하는 Templatefield로 변환로 변환 되어야 합니다.Since the CompanyName field is required, it should be converted into a TemplateField that includes a RequiredFieldValidator. 관심이 있는 독자를 위한 연습으로 남겨 둡니다.I leave this as an exercise for the interested reader. BoundField을 Templatefield로 변환로 변환 하 고 유효성 검사 컨트롤을 추가 하는 방법에 대 한 단계별 지침은 인터페이스 편집 및 삽입에 유효성 검사 컨트롤 추가 자습서를 참조 하세요.Consult the Adding Validation Controls to the Editing and Inserting Interfaces tutorial for step-by-step instructions on converting a BoundField to a TemplateField and adding validation controls.

요약Summary

테이블에 대 한 스키마를 정의 하는 경우 계산 열을 포함할 수 Microsoft SQL Server.When defining the schema for a table, Microsoft SQL Server allows the inclusion of computed columns. 이러한 열은 일반적으로 동일한 레코드의 다른 열에 있는 값을 참조 하는 식에서 계산 된 값을 갖는 열입니다.These are columns whose values are calculated from an expression that usually references the values from other columns in the same record. 계산 열의 값은 식을 기반으로 하기 때문에 읽기 전용 이며 INSERT 또는 UPDATE 문에서 값을 할당할 수 없습니다.Since the values for computed columns are based on an expression, they are read-only and cannot be assigned a value in an INSERT or UPDATE statement. 이는 TableAdapter의 주 쿼리에서 계산 열을 사용 하 여 해당 INSERT, UPDATEDELETE 문을 자동으로 생성 하려고 하는 경우의 문제를 소개 합니다.This introduces challenges when using a computed column in the main query of a TableAdapter that tries to automatically generate corresponding INSERT, UPDATE, and DELETE statements.

이 자습서에서는 계산 열에 의해 발생 하는 문제를 회피 하는 기술에 대해 설명 했습니다.In this tutorial we discussed techniques for circumventing the challenges posed by computed columns. 특히 임시 SQL 문을 사용 하는 Tableadapter에서 brittleness 내재 된 저장 프로시저를 사용 했습니다.In particular, we used stored procedures in our TableAdapter to overcome the brittleness inherent in TableAdapters that use ad-hoc SQL statements. TableAdapter 마법사에서 새 저장 프로시저를 만들 때 데이터 수정 저장 프로시저가 생성 되지 않도록 하기 때문에 기본 쿼리에서 처음에 계산 열을 생략 하는 것이 중요 합니다.When having the TableAdapter wizard create new stored procedures, it is important that we have the main query initially omit any computed columns because their presence prevents the data modification stored procedures from being generated. TableAdapter를 처음 구성한 후에는 해당 SelectCommand 저장 프로시저를 다시 계산 하 여 계산 열을 포함할 수 있습니다.After the TableAdapter has been initially configured, its SelectCommand stored procedure can be retooled to include any computed columns.

행복 한 프로그래밍Happy Programming!

저자 정보About the Author

Scott Mitchell(7 개의 ASP/ASP. NET books 및 4GuysFromRolla.com창립자)은 1998부터 Microsoft 웹 기술을 사용 하 여 작업 했습니다.Scott Mitchell, author of seven ASP/ASP.NET books and founder of 4GuysFromRolla.com, has been working with Microsoft Web technologies since 1998. Scott은 독립 컨설턴트, 강사 및 기록기로 작동 합니다.Scott works as an independent consultant, trainer, and writer. 최신 책은 24 시간 이내에 ASP.NET 2.0을 sams teach yourself것입니다.His latest book is Sams Teach Yourself ASP.NET 2.0 in 24 Hours. mitchell@4GuysFromRolla.com에 도달할 수 있습니다 .He can be reached at mitchell@4GuysFromRolla.com. 또는 블로그를 통해 http://ScottOnWriting.NET에서 찾을 수 있습니다.or via his blog, which can be found at http://ScottOnWriting.NET.

특별히 감사 합니다.Special Thanks To

이 자습서 시리즈는 많은 유용한 검토자가 검토 했습니다.This tutorial series was reviewed by many helpful reviewers. 이 자습서의 리드 검토자는 Hilton Geisenow와 Teresa Murphy 였습니다.Lead reviewers for this tutorial were Hilton Geisenow and Teresa Murphy. 예정 된 MSDN 문서를 검토 하는 데 관심이 있나요?Interested in reviewing my upcoming MSDN articles? 그렇다면mitchell@4GuysFromRolla.com에서 줄을 삭제 합니다.If so, drop me a line at mitchell@4GuysFromRolla.com.