'ASP.NET'에 해당되는 글 82건

OS/Windows Server

보통 서버환경에서 서버나 프로그램에 관한 모니터링에 관리 도구에 있는 성능카운터를 활용합니다.

 

 

 

서버에 ASP.NET등으로 웹 프로그램을 운용한다면 다음과 같이 ASP.NET에 적용되는 성능카운터등을 확인할 수 있습니다.

 

 

 Application Restarts

 서버가 동작하는 동안 프로그램이 재시작된 횟수

 Application Running

 현재 동작중인 프로그램 수

 Audit Failure Events Raised

 프로그램 감사 실패 횟수

 Audit Success Events Raised

 프로그램 감사 성공 횟수

 Error Events Raised

 프로그램이 발생시킨 오류 이벤트 횟수

 Infrastructure Error Events Raised

 HTTP 오류 이벤트 횟수

 Request Error Events Raised

 프로그램이 발생시킨 런타임 이벤트 횟수

 Request Execution Time

 가장 최근 요청을 처리하는데 걸린 시간 (1/1000초)

 Request Waite Time

 큐에서 가장 최근요청이 대기한 시간(1/1000초)

 Requests Current

 모든 요청 수, 해당 카운터는 processModel에 정의된 requestQueueLimit 값을 기준으로 초과되면 요청이 거부됨

 Requests Disconnected

 연결이 끊어지거나 사용자가 종료한 요청 수

 Requests Queued

 큐에 대기중인 요청 수

 Requests Rejected

 큐가 가득찬 상태에서 거부된 요청 수

 State Server Sessions Abandoned

 명시적으로 중단된 세션 수

 State Server Sessions Active

 현재 활성화된 세션 수

 State Server Sessions Timed Out

 시간 초과된 세션 수

 State Server Sessions Total

 총 세션 수

 Worker Process Restarts

 작업자 프로세스를 다시 시작한 횟수

 Worker Processes Running

 실행중인 작업자 프로세스 수

 

0 0
Programming/.NET

ASP.NET 에서 Expressions 는 지정된 데이터 값을 반환하기 위해 런타임에서 파싱되는 특정 구문에 해당합니다. 이를 테면 SqlDataSource 컨트롤 사용시 ConnectionString 속성에 DB연결정보 제공을 위해서 다음과 같은 형태의 값을 지정하곤 했는데 이것이 바로 Expressions 에 해당합니다.

<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:new_connection %>" SelectCommand="SELECT Top 100 * FROM [Person].[PersonPhone]"></asp:SqlDataSource>

ASP.NET 은 aspx 페이지를 파싱할때 SqlDataSource 컨트롤에서 <%$ %> 내용이 포함된 구문을 발견하면 Web.config 로 부터 데이터베이스 연결정보를 가져옵니다. 이때 Expressions 에 사용된 ConnectionStrings 라는 접두사는 ConnectionStringsExpressionBuilder 클래스를 사용해 해당 Expressions 을 파싱할것을 알려주게 됩니다.

ConnectionStringsExpressionBuilder 클래스는 Expression 을 파싱하는데 사용되는 Expression Builders 중 하나로서 ASP.NET 은 이러한 Expression Builders 를 다수 포함하고 있습니다. 그 중에서 Web.config 의 DB 연결정보값을 가져오기 위한 것중 하나가 바로 ConnectionStringsExpressionBuilder 에 해당합니다.

또한 Expressions 에서 AppSettings 접두사를 사용하면 이것은 Web.config 파일의 appSettings 섹션 에서 지정한 값을 가져와야 한다는 것을 의미하는 것으로 AppSettingsExpressionBuilder 클래스를 사용해 파싱을 시도합니다.

<appSettings>
 <add key="test" value="테스트" />
</appSettings>

▶Web.config 의 appSettings 설정

<asp:Label ID="Label1" runat="server" Text="<%$ AppSettings:test %>"></asp:Label>

▶ <코드 1-1>

<코드 1-1>은 Web.config 의 appSettings 에서 지정한 Key 에 해당하는 값을 가져옵니다.

Resources 접두사는 웹프로젝트의 로컬리소스를 가져오며 ResourceExpressionBuilder 클래스를 사용해 파싱됩니다.

<asp:Label ID="Label1" runat="server"Text="<%$ Resource: LocalResources.test %>"></asp:Label>

뿐만 아니라 ASP.NET 은 위에서 처럼 정해진 Expressions 이외에 System.Web.Compilation.ExpressionB
uilder 클래스를 기반으로 개발자 자신만의 Expression 을 직접 구현하여 사용할 수도 있습니다.

[ExpressionPrefix("mEx")][ExpressionEditor("myExpressionEditor")]
public class myExpression : System.Web.Compilation.ExpressionBuilder
{
    public override System.CodeDom.CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
    {
        return new CodeCastExpression("String", new CodePrimitiveExpression("Hello"));
    }
}

▶ <코드 1-2>

<코드 1-2>는 ExpressionBuilder 클래스에서 파생된 myExpression 클래스를 정의한 것으로서 새로운 ExpressionBuilder 클래스를 생성한 것입니다. 클래스에서 지정된 ExpressionPrefix 와 ExpressionEditor 속성은 .NET 으로 하여금 해당 클래스가 Expression 에 사용되는 클래스임을 알려주기 위한 것으로 실제 Expression 이 파싱될때 그에 맞는 적절한 ExpressionBuilder 클래스를 찾아낼 수 있도록 합니다.

myExpression 클래스안에서 오버라이드(재정의)된 GetCodeExpression 메소드는 네임스페이스 상으로 CodeDom 하위에 속합니다. CodeDom 은 ASP.NET 이 런타임시에 코드를 동적으로 생성하고 생성된 코드를 실행한 결과를 반환하는데 사용되는 기반클래스입니다. Expression 에서 CodeDom 이 언급되는 이유는 직접 구현한 ExpressionBuilder 클래스 자체가 코드가 되어 동작하는 것이 아니라 런타임에 .NET 으로 하여금 어떠한 코드를 생성하고 실행해야 하는지를 알려주는 이정표같은 역활을 하기 때문입니다. GetCodeExpression 안에서 작성된 CodeCastExpression 메소드는 형변환을 수행하기 위한 코드를 생성해야 함을 나타내며 실제 런타임에서 C#의 경우 ((Int64)(1000)) 과 같은 코드를 생성해 내고 동작을 수행하게 되는 것입니다.

GetCodeExpression 메소드는 대략 3가지 정도의 파라메터를 가지고 있는데 이 중 두개의 파라메터에 주목해 주세요. 첫번째 파라메터인 entry 는 Expression 이 사용될때 어느 속성에 연결되어 있는지를 알아내기 위한 것입니다. 예를 들면 <코드 1-1>에서 Label 의 Text 속성에 Expression 이 사용되었는데 이때 entry 는 Label 컨트롤및 여기에 바인딩된 Text 속성에 관한 정보를 가지게 됩니다.

두번째 파라메터인 parseData 는 ParseExpression 메소드에 의해 파싱되는 데이터를 포함하고 있습니다. 사실 <코드 1-2>와 같이 ExpressionBuilder 를 생성하고 다음과 같이 Expression 을 바인딩했다고 했을때

<asp:Label ID="Label1" runat="server" Text="<%$ mEx:hi %>"></asp:Label>

이때 mEx 접두사 다음에 사용된 hi라는 데이터값을 읽고 저장하는 파라메터가 바로 parseData 에 해당합니다.

다만 실제로 동작결과를 살펴보면 parseData 에는 아무런 값도 없고(null) 그저 Hello 이라는 값만이 나오게 됩니다. parseData 파라메터를 제대로 활용하려면 우선 값을 파싱하기 위한 ParseExpression 메소드를 오버라이드해야 하며 parseData 에 따른 값을 반환시키려면 <코드 1-2>에서 Hello 이라는 값 대신 parseData 로 바꿔줘야 합니다.

[ExpressionPrefix("mEx")][ExpressionEditor("myExpressionEditor")]
public class myExpression : System.Web.Compilation.ExpressionBuilder
{
    public override System.CodeDom.CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
    {
        return new CodeCastExpression("String", new CodePrimitiveExpression(parsedData));
    }

    public override object ParseExpression(string expression, Type propertyType, ExpressionBuilderContext context)
    {
        return expression;
    }
}

만약 aspx 페이지의 Page 지시에서 CompilationMode 속성이 Naver 등으로 설정되어 페이지가 no-compile 모드로 동작하는 경우에는 위 방법 대신에 SupportsEvaluate 속성과 EvaluateExpression 메소드를 오버라이드해서 Expression 의 값을 가져와야 합니다.

[ExpressionPrefix("mEx")][ExpressionEditor("myExpressionEditor")]
public class myExpression : System.Web.Compilation.ExpressionBuilder
{
    public override System.CodeDom.CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
    {
        return new CodeCastExpression("String", new CodePrimitiveExpression(parsedData));
    }

    public override object ParseExpression(string expression, Type propertyType, ExpressionBuilderContext context)
    {
        return expression;
    }

    public override bool SupportsEvaluate
    {
        get { return true; }
    }

    public override object EvaluateExpression(object target, BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
    {
        return parsedData;
    }
}

SupportsEvaluate 속성을 통해 Evaluate 사용을 허가하고 EvaluateExpression 메소드를 재정의하면 이 메소드가 페이지가 no-compile 모드일때 GetCodeExpression 메소드대신 Expression 값을 가져오는데 사용됩니다.

마지막으로 ExpressionBuilder 를 생성하고 나면 web.config 파일의 expressionBuilders 노드에 해당 클래스의 존재와 접두사를 추가함으로서 ASP.NET 이 런타임에 Builder 클래스를 찾을 수 있도록 해야 합니다.

<system.web>
  <compilation debug="true" targetFramework="4.0">
    <expressionBuilders>
      <add expressionPrefix="mEx" type="Webtest.App_Code.myExpression" />
    </expressionBuilders>
  </compilation>
</system.web>

0 0
Programming/.NET
ASP.NET 은 XML 데이터의 바인딩을 위해 Xpath 구문을 사용할 수 있습니다. 다만 데이터 소스가 XML 이므로 XmlDataSource 를 사용해 XML 을 바인딩해야 합니다.
<%# XPathBinder.Eval(Container.DataItem, "Customers/Customer/CompanyName"%>
기본적인 구문으로서 XPathBinder 클래스를 사용해 Eval 메소드를 호출하여 대상 XML 의 원하는 경로를 XPath 형식으로 지정해 주면 됩니다.

혹은 다음과 같이 간략하게 XPath 를 지정해 줄 수도 있습니다.
<%# XPath("Customers/Customer/CompanyName"%>
Paramter 를 추가를 통해 원하는 Format 을 지정하면 바인딩되는 데이터에 대해 지정한 포멧을 적용시킬 수 잇습니다.
<%# XPath("Orders/Order/OrderDate""{0:yyyy-MM-dd}"%>
이제 까지의 방법은 단일 node 값을 가져오는 방법입니다. 다수의 node 를 array 형식으로 가져오려면 XPathBinder 클래스의 Select 메소드를 사용해야 합니다.
<asp:XmlDataSource ID="XmlDataSource1" runat="server" XPath="Root" DataFile="sample.xml"></asp:XmlDataSource>
 
<asp:FormView id="FormView1" runat="server" DataSourceID="XmlDataSource1">
    <ItemTemplate>
        <asp:Repeater ID="Repeater1" runat="server" DataSource='<%# XPathBinder.Select(Container.DataItem, "Orders/Order"%>'>
            <HeaderTemplate>
                <table>
            </HeaderTemplate>
                <ItemTemplate>
                <tr>
                    <td>
                        <%# XPath("CustomerID"%>
                    </td>
                    <td>
                        <%# XPath("EmployeeID"%>
                    </td>
                </tr>
                </ItemTemplate>
            <FooterTemplate>
                </table>
            </FooterTemplate>
        </asp:Repeater>
    </ItemTemplate>
</asp:FormView>
위 예제에서는 FormView 에 XmlDataSource 를 지정하고 하위에 Repeater 컨트롤을 사용하여 Array 형태로 반환되는 node 값을 순환해 표시하도록 한것입니다.
 
Repeater 에서는 DataSource 의 대상으로 XPathBinder 클래스의 Select 메소드를 호출하였는데 이때 사용한 XPath 구문의 대상이 바로 FormView 에서 데이터소스로 지정된 sample.xml 인 것입니다. 결국 Select 메소드 호출로 인해서 최종적으로 Root/Orders 하위에 있는 모든 XML node 배열을 가져오게 되고 Repeater 가 순환하면서 Order 노드안에 있는 CustomerID 와 EmployeeID 를 출력하게 됩니다.

참고로 XPathBinder.Select 는 XPathSelect 메소드로 대신 사용될 수 있습니다.

아래는 sample.xml 파일의 구조입니다.

<?xml version="1.0" encoding="utf-8"?>
<Root>
  <Customers>
    <Customer CustomerID="GREAL">
      <CompanyName>Great Lakes Food Market</CompanyName>
      <ContactName>Howard Snyder</ContactName>
      <ContactTitle>Marketing Manager</ContactTitle>
      <Phone>(503) 555-7555</Phone>
      <FullAddress>
        <Address>2732 Baker Blvd.</Address>
        <City>Eugene</City>
        <Region>OR</Region>
        <PostalCode>97403</PostalCode>
        <Country>USA</Country>
      </FullAddress>
    </Customer>
    <Customer CustomerID="HUNGC">
      <CompanyName>Hungry Coyote Import Store</CompanyName>
      <ContactName>Yoshi Latimer</ContactName>
      <ContactTitle>Sales Representative</ContactTitle>
      <Phone>(503) 555-6874</Phone>
      <Fax>(503) 555-2376</Fax>
      <FullAddress>
        <Address>City Center Plaza 516 Main St.</Address>
        <City>Elgin</City>
        <Region>OR</Region>
        <PostalCode>97827</PostalCode>
        <Country>USA</Country>
      </FullAddress>
    </Customer>
    <Customer CustomerID="LAZYK">
      <CompanyName>Lazy K Kountry Store</CompanyName>
      <ContactName>John Steel</ContactName>
      <ContactTitle>Marketing Manager</ContactTitle>
      <Phone>(509) 555-7969</Phone>
      <Fax>(509) 555-6221</Fax>
      <FullAddress>
        <Address>12 Orchestra Terrace</Address>
        <City>Walla Walla</City>
        <Region>WA</Region>
        <PostalCode>99362</PostalCode>
        <Country>USA</Country>
      </FullAddress>
    </Customer>
    <Customer CustomerID="LETSS">
      <CompanyName>Let's Stop N Shop</CompanyName>
      <ContactName>Jaime Yorres</ContactName>
      <ContactTitle>Owner</ContactTitle>
      <Phone>(415) 555-5938</Phone>
      <FullAddress>
        <Address>87 Polk St. Suite 5</Address>
        <City>San Francisco</City>
        <Region>CA</Region>
        <PostalCode>94117</PostalCode>
        <Country>USA</Country>
      </FullAddress>
    </Customer>
  </Customers>
  <Orders>
    <Order>
      <CustomerID>GREAL</CustomerID>
      <EmployeeID>6</EmployeeID>
      <OrderDate>1997-05-06T00:00:00</OrderDate>
      <RequiredDate>1997-05-20T00:00:00</RequiredDate>
      <ShipInfo ShippedDate="1997-05-09T00:00:00">
        <ShipVia>2</ShipVia>
        <Freight>3.35</Freight>
        <ShipName>Great Lakes Food Market</ShipName>
        <ShipAddress>2732 Baker Blvd.</ShipAddress>
        <ShipCity>Eugene</ShipCity>
        <ShipRegion>OR</ShipRegion>
        <ShipPostalCode>97403</ShipPostalCode>
        <ShipCountry>USA</ShipCountry>
      </ShipInfo>
    </Order>
    <Order>
      <CustomerID>GREAL</CustomerID>
      <EmployeeID>8</EmployeeID>
      <OrderDate>1997-07-04T00:00:00</OrderDate>
      <RequiredDate>1997-08-01T00:00:00</RequiredDate>
      <ShipInfo ShippedDate="1997-07-14T00:00:00">
        <ShipVia>2</ShipVia>
        <Freight>4.42</Freight>
        <ShipName>Great Lakes Food Market</ShipName>
        <ShipAddress>2732 Baker Blvd.</ShipAddress>
        <ShipCity>Eugene</ShipCity>
        <ShipRegion>OR</ShipRegion>
        <ShipPostalCode>97403</ShipPostalCode>
        <ShipCountry>USA</ShipCountry>
      </ShipInfo>
    </Order>
    <Order>
      <CustomerID>GREAL</CustomerID>
      <EmployeeID>1</EmployeeID>
      <OrderDate>1997-07-31T00:00:00</OrderDate>
      <RequiredDate>1997-08-28T00:00:00</RequiredDate>
      <ShipInfo ShippedDate="1997-08-05T00:00:00">
        <ShipVia>2</ShipVia>
        <Freight>116.53</Freight>
        <ShipName>Great Lakes Food Market</ShipName>
        <ShipAddress>2732 Baker Blvd.</ShipAddress>
        <ShipCity>Eugene</ShipCity>
        <ShipRegion>OR</ShipRegion>
        <ShipPostalCode>97403</ShipPostalCode>
        <ShipCountry>USA</ShipCountry>
      </ShipInfo>
    </Order>
    <Order>
      <CustomerID>GREAL</CustomerID>
      <EmployeeID>4</EmployeeID>
      <OrderDate>1997-07-31T00:00:00</OrderDate>
      <RequiredDate>1997-08-28T00:00:00</RequiredDate>
      <ShipInfo ShippedDate="1997-08-04T00:00:00">
        <ShipVia>2</ShipVia>
        <Freight>18.53</Freight>
        <ShipName>Great Lakes Food Market</ShipName>
        <ShipAddress>2732 Baker Blvd.</ShipAddress>
        <ShipCity>Eugene</ShipCity>
        <ShipRegion>OR</ShipRegion>
        <ShipPostalCode>97403</ShipPostalCode>
        <ShipCountry>USA</ShipCountry>
      </ShipInfo>
    </Order>
    <Order>
      <CustomerID>GREAL</CustomerID>
      <EmployeeID>6</EmployeeID>
      <OrderDate>1997-09-04T00:00:00</OrderDate>
      <RequiredDate>1997-10-02T00:00:00</RequiredDate>
      <ShipInfo ShippedDate="1997-09-10T00:00:00">
        <ShipVia>1</ShipVia>
        <Freight>57.15</Freight>
        <ShipName>Great Lakes Food Market</ShipName>
        <ShipAddress>2732 Baker Blvd.</ShipAddress>
        <ShipCity>Eugene</ShipCity>
        <ShipRegion>OR</ShipRegion>
        <ShipPostalCode>97403</ShipPostalCode>
        <ShipCountry>USA</ShipCountry>
      </ShipInfo>
    </Order>
    <Order>
      <CustomerID>GREAL</CustomerID>
      <EmployeeID>3</EmployeeID>
      <OrderDate>1997-09-25T00:00:00</OrderDate>
      <RequiredDate>1997-10-23T00:00:00</RequiredDate>
      <ShipInfo ShippedDate="1997-09-30T00:00:00">
        <ShipVia>3</ShipVia>
        <Freight>76.13</Freight>
        <ShipName>Great Lakes Food Market</ShipName>
        <ShipAddress>2732 Baker Blvd.</ShipAddress>
        <ShipCity>Eugene</ShipCity>
        <ShipRegion>OR</ShipRegion>
        <ShipPostalCode>97403</ShipPostalCode>
        <ShipCountry>USA</ShipCountry>
      </ShipInfo>
    </Order>
    <Order>
      <CustomerID>GREAL</CustomerID>
      <EmployeeID>4</EmployeeID>
      <OrderDate>1998-01-06T00:00:00</OrderDate>
      <RequiredDate>1998-02-03T00:00:00</RequiredDate>
      <ShipInfo ShippedDate="1998-02-04T00:00:00">
        <ShipVia>2</ShipVia>
        <Freight>719.78</Freight>
        <ShipName>Great Lakes Food Market</ShipName>
        <ShipAddress>2732 Baker Blvd.</ShipAddress>
        <ShipCity>Eugene</ShipCity>
        <ShipRegion>OR</ShipRegion>
        <ShipPostalCode>97403</ShipPostalCode>
        <ShipCountry>USA</ShipCountry>
      </ShipInfo>
    </Order>
    <Order>
      <CustomerID>GREAL</CustomerID>
      <EmployeeID>3</EmployeeID>
      <OrderDate>1998-03-09T00:00:00</OrderDate>
      <RequiredDate>1998-04-06T00:00:00</RequiredDate>
      <ShipInfo ShippedDate="1998-03-18T00:00:00">
        <ShipVia>2</ShipVia>
        <Freight>33.68</Freight>
        <ShipName>Great Lakes Food Market</ShipName>
        <ShipAddress>2732 Baker Blvd.</ShipAddress>
        <ShipCity>Eugene</ShipCity>
        <ShipRegion>OR</ShipRegion>
        <ShipPostalCode>97403</ShipPostalCode>
        <ShipCountry>USA</ShipCountry>
      </ShipInfo>
    </Order>
    <Order>
      <CustomerID>GREAL</CustomerID>
      <EmployeeID>3</EmployeeID>
      <OrderDate>1998-04-07T00:00:00</OrderDate>
      <RequiredDate>1998-05-05T00:00:00</RequiredDate>
      <ShipInfo ShippedDate="1998-04-15T00:00:00">
        <ShipVia>2</ShipVia>
        <Freight>25.19</Freight>
        <ShipName>Great Lakes Food Market</ShipName>
        <ShipAddress>2732 Baker Blvd.</ShipAddress>
        <ShipCity>Eugene</ShipCity>
        <ShipRegion>OR</ShipRegion>
        <ShipPostalCode>97403</ShipPostalCode>
        <ShipCountry>USA</ShipCountry>
      </ShipInfo>
    </Order>
    <Order>
      <CustomerID>GREAL</CustomerID>
      <EmployeeID>4</EmployeeID>
      <OrderDate>1998-04-22T00:00:00</OrderDate>
      <RequiredDate>1998-05-20T00:00:00</RequiredDate>
      <ShipInfo>
        <ShipVia>3</ShipVia>
        <Freight>18.84</Freight>
        <ShipName>Great Lakes Food Market</ShipName>
        <ShipAddress>2732 Baker Blvd.</ShipAddress>
        <ShipCity>Eugene</ShipCity>
        <ShipRegion>OR</ShipRegion>
        <ShipPostalCode>97403</ShipPostalCode>
        <ShipCountry>USA</ShipCountry>
      </ShipInfo>
    </Order>
    <Order>
      <CustomerID>GREAL</CustomerID>
      <EmployeeID>4</EmployeeID>
      <OrderDate>1998-04-30T00:00:00</OrderDate>
      <RequiredDate>1998-06-11T00:00:00</RequiredDate>
      <ShipInfo>
        <ShipVia>3</ShipVia>
        <Freight>14.01</Freight>
        <ShipName>Great Lakes Food Market</ShipName>
        <ShipAddress>2732 Baker Blvd.</ShipAddress>
        <ShipCity>Eugene</ShipCity>
        <ShipRegion>OR</ShipRegion>
        <ShipPostalCode>97403</ShipPostalCode>
        <ShipCountry>USA</ShipCountry>
      </ShipInfo>
    </Order>
    <Order>
      <CustomerID>HUNGC</CustomerID>
      <EmployeeID>3</EmployeeID>
      <OrderDate>1996-12-06T00:00:00</OrderDate>
      <RequiredDate>1997-01-03T00:00:00</RequiredDate>
      <ShipInfo ShippedDate="1996-12-09T00:00:00">
        <ShipVia>2</ShipVia>
        <Freight>20.12</Freight>
        <ShipName>Hungry Coyote Import Store</ShipName>
        <ShipAddress>City Center Plaza 516 Main St.</ShipAddress>
        <ShipCity>Elgin</ShipCity>
        <ShipRegion>OR</ShipRegion>
        <ShipPostalCode>97827</ShipPostalCode>
        <ShipCountry>USA</ShipCountry>
      </ShipInfo>
    </Order>
    <Order>
      <CustomerID>HUNGC</CustomerID>
      <EmployeeID>1</EmployeeID>
      <OrderDate>1996-12-25T00:00:00</OrderDate>
      <RequiredDate>1997-01-22T00:00:00</RequiredDate>
      <ShipInfo ShippedDate="1997-01-03T00:00:00">
        <ShipVia>3</ShipVia>
        <Freight>30.34</Freight>
        <ShipName>Hungry Coyote Import Store</ShipName>
        <ShipAddress>City Center Plaza 516 Main St.</ShipAddress>
        <ShipCity>Elgin</ShipCity>
        <ShipRegion>OR</ShipRegion>
        <ShipPostalCode>97827</ShipPostalCode>
        <ShipCountry>USA</ShipCountry>
      </ShipInfo>
    </Order>
    <Order>
      <CustomerID>HUNGC</CustomerID>
      <EmployeeID>3</EmployeeID>
      <OrderDate>1997-01-15T00:00:00</OrderDate>
      <RequiredDate>1997-02-12T00:00:00</RequiredDate>
      <ShipInfo ShippedDate="1997-01-24T00:00:00">
        <ShipVia>1</ShipVia>
        <Freight>0.2</Freight>
        <ShipName>Hungry Coyote Import Store</ShipName>
        <ShipAddress>City Center Plaza 516 Main St.</ShipAddress>
        <ShipCity>Elgin</ShipCity>
        <ShipRegion>OR</ShipRegion>
        <ShipPostalCode>97827</ShipPostalCode>
        <ShipCountry>USA</ShipCountry>
      </ShipInfo>
    </Order>
    <Order>
      <CustomerID>HUNGC</CustomerID>
      <EmployeeID>4</EmployeeID>
      <OrderDate>1997-07-16T00:00:00</OrderDate>
      <RequiredDate>1997-08-13T00:00:00</RequiredDate>
      <ShipInfo ShippedDate="1997-07-21T00:00:00">
        <ShipVia>1</ShipVia>
        <Freight>45.13</Freight>
        <ShipName>Hungry Coyote Import Store</ShipName>
        <ShipAddress>City Center Plaza 516 Main St.</ShipAddress>
        <ShipCity>Elgin</ShipCity>
        <ShipRegion>OR</ShipRegion>
        <ShipPostalCode>97827</ShipPostalCode>
        <ShipCountry>USA</ShipCountry>
      </ShipInfo>
    </Order>
    <Order>
      <CustomerID>HUNGC</CustomerID>
      <EmployeeID>8</EmployeeID>
      <OrderDate>1997-09-08T00:00:00</OrderDate>
      <RequiredDate>1997-10-06T00:00:00</RequiredDate>
      <ShipInfo ShippedDate="1997-10-15T00:00:00">
        <ShipVia>1</ShipVia>
        <Freight>111.29</Freight>
        <ShipName>Hungry Coyote Import Store</ShipName>
        <ShipAddress>City Center Plaza 516 Main St.</ShipAddress>
        <ShipCity>Elgin</ShipCity>
        <ShipRegion>OR</ShipRegion>
        <ShipPostalCode>97827</ShipPostalCode>
        <ShipCountry>USA</ShipCountry>
      </ShipInfo>
    </Order>
    <Order>
      <CustomerID>LAZYK</CustomerID>
      <EmployeeID>1</EmployeeID>
      <OrderDate>1997-03-21T00:00:00</OrderDate>
      <RequiredDate>1997-04-18T00:00:00</RequiredDate>
      <ShipInfo ShippedDate="1997-04-10T00:00:00">
        <ShipVia>3</ShipVia>
        <Freight>7.48</Freight>
        <ShipName>Lazy K Kountry Store</ShipName>
        <ShipAddress>12 Orchestra Terrace</ShipAddress>
        <ShipCity>Walla Walla</ShipCity>
        <ShipRegion>WA</ShipRegion>
        <ShipPostalCode>99362</ShipPostalCode>
        <ShipCountry>USA</ShipCountry>
      </ShipInfo>
    </Order>
    <Order>
      <CustomerID>LAZYK</CustomerID>
      <EmployeeID>8</EmployeeID>
      <OrderDate>1997-05-22T00:00:00</OrderDate>
      <RequiredDate>1997-06-19T00:00:00</RequiredDate>
      <ShipInfo ShippedDate="1997-06-26T00:00:00">
        <ShipVia>2</ShipVia>
        <Freight>11.92</Freight>
        <ShipName>Lazy K Kountry Store</ShipName>
        <ShipAddress>12 Orchestra Terrace</ShipAddress>
        <ShipCity>Walla Walla</ShipCity>
        <ShipRegion>WA</ShipRegion>
        <ShipPostalCode>99362</ShipPostalCode>
        <ShipCountry>USA</ShipCountry>
      </ShipInfo>
    </Order>
    <Order>
      <CustomerID>LETSS</CustomerID>
      <EmployeeID>1</EmployeeID>
      <OrderDate>1997-06-25T00:00:00</OrderDate>
      <RequiredDate>1997-07-23T00:00:00</RequiredDate>
      <ShipInfo ShippedDate="1997-07-04T00:00:00">
        <ShipVia>2</ShipVia>
        <Freight>13.73</Freight>
        <ShipName>Let's Stop N Shop</ShipName>
        <ShipAddress>87 Polk St. Suite 5</ShipAddress>
        <ShipCity>San Francisco</ShipCity>
        <ShipRegion>CA</ShipRegion>
        <ShipPostalCode>94117</ShipPostalCode>
        <ShipCountry>USA</ShipCountry>
      </ShipInfo>
    </Order>
    <Order>
      <CustomerID>LETSS</CustomerID>
      <EmployeeID>8</EmployeeID>
      <OrderDate>1997-10-27T00:00:00</OrderDate>
      <RequiredDate>1997-11-24T00:00:00</RequiredDate>
      <ShipInfo ShippedDate="1997-11-05T00:00:00">
        <ShipVia>2</ShipVia>
        <Freight>51.44</Freight>
        <ShipName>Let's Stop N Shop</ShipName>
        <ShipAddress>87 Polk St. Suite 5</ShipAddress>
        <ShipCity>San Francisco</ShipCity>
        <ShipRegion>CA</ShipRegion>
        <ShipPostalCode>94117</ShipPostalCode>
        <ShipCountry>USA</ShipCountry>
      </ShipInfo>
    </Order>
    <Order>
      <CustomerID>LETSS</CustomerID>
      <EmployeeID>6</EmployeeID>
      <OrderDate>1997-11-10T00:00:00</OrderDate>
      <RequiredDate>1997-12-08T00:00:00</RequiredDate>
      <ShipInfo ShippedDate="1997-11-21T00:00:00">
        <ShipVia>2</ShipVia>
        <Freight>45.97</Freight>
        <ShipName>Let's Stop N Shop</ShipName>
        <ShipAddress>87 Polk St. Suite 5</ShipAddress>
        <ShipCity>San Francisco</ShipCity>
        <ShipRegion>CA</ShipRegion>
        <ShipPostalCode>94117</ShipPostalCode>
        <ShipCountry>USA</ShipCountry>
      </ShipInfo>
    </Order>
    <Order>
      <CustomerID>LETSS</CustomerID>
      <EmployeeID>4</EmployeeID>
      <OrderDate>1998-02-12T00:00:00</OrderDate>
      <RequiredDate>1998-03-12T00:00:00</RequiredDate>
      <ShipInfo ShippedDate="1998-02-13T00:00:00">
        <ShipVia>2</ShipVia>
        <Freight>90.97</Freight>
        <ShipName>Let's Stop N Shop</ShipName>
        <ShipAddress>87 Polk St. Suite 5</ShipAddress>
        <ShipCity>San Francisco</ShipCity>
        <ShipRegion>CA</ShipRegion>
        <ShipPostalCode>94117</ShipPostalCode>
        <ShipCountry>USA</ShipCountry>
      </ShipInfo>
    </Order>
  </Orders>
</Root>
0 0
Programming/.NET

 1. TreeView

 

TreeView 컨트롤은 계층화된 데이터구조를 표현하는데 사용되는 컨트롤입니다. 때문에 TreeView 의 데이터소스로는 XmlDataSource 나 SiteMapDataSource 컨트롤(IHierarchicalDataSource 인터페이스를 상속받는)만이 사용될 수 있습니다.

 

 2. SiteMap 연동

 

프로젝트에 존재하는 sitemap 파일을 TreeView와 연동하려면 먼저 sitemap데이터를 연결짓는 SiteMapDataSource 컨트롤을 배치하고 TreeView의 DataSourceID에 해당 Data컨트롤의 ID를 지정하면 됩니다.

<asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server" />
<asp:TreeView ID="TreeView1" runat="server" DataSourceID="SiteMapDataSource1"></asp:TreeView>

참고로 SiteMapDataSource 는 해당 프로젝트에 Web.sitemap 과 같은 사이트맵 파일이 존재해야 합니다.

 

 

위 예제는 SiteMapDataSource 컨트롤과 TreeView컨트롤을 매핑한 결과입니다.

 

 3. XML 연동

 

XML은 XML파일을 바인딩하는 XmlDataSource 컨트롤을 통해서 연동이 가능합니다. 우선 다음글에서와 같은 내용의 books.xml파일을 생성하고

 

2016/01/18 - [Programming/ASP.NET] - [ASP.NET] XML - 1

 

XmlDataSource 컨트롤로 해당 XML파일을 연결해 보겠습니다.

 

<asp:XmlDataSource ID="XmlDataSource1" runat="server" DataFile="~/books.xml">

</asp:XmlDataSource>

 

그리고 TreeView의 DataSourceID를 XmlDataSource의 ID값으로 설정하면 XML내용이 완벽히 바인딩됩니다.

 

 

 

하지만 경우에 따라 바인딩되는 요소를 제어하고 싶은 경우가 있는데 그럴때는 TreeView의 하위 요소인 DataBindings 요소를 사용하면 됩니다.

 

<asp:TreeView ID="TreeView1" runat="server" DataSourceID="XmlDataSource1">
    <DataBindings>
        <asp:TreeNodeBinding DataMember="catalog" Text="서적관리" />
        <asp:TreeNodeBinding DataMember="book" TextField="id" />
        <asp:TreeNodeBinding DataMember="author" TextField="#InnerText" />
    </DataBindings>
</asp:TreeView>

 

TreeNodeBinding 요소는 XML 의 요소와 1:1로 매핑되며 DataMember 속성으로 실제 매핑될 XML요소를 지정합니다. Text 속성은 XML요소의 내용과는 상관없이 원하는 문자열을 표시하지만 TextField속성을 사용하여 XML요소의 속성을 지정하면 해당 속성값이 문자열로 표시됩니다. 예제에서의 두번째 TextField에는 #InnerText 가 지정되었는데 이것은 속성이 아닌 XML내부의 문자열을 가져오겠다는 의미입니다.

 

 4. 내장 스타일

 

Visual Studio의 디자인 모드에서 스마트태그를 선택하면 다음과 같이 자체지원하는 스타일을 적용할 수 있습니다.

 

 

내장 스타일을 적용하면 해당 스타일 고유의 노드아이콘이 표시되지만 원하는 경우 직접 제작한 이미지를 노드아이콘으로 적용할 수 있습니다.

 

<asp:TreeView ID="TreeView1" runat="server" DataSourceID="XmlDataSource1" ShowCheckBoxes="All" 

CollapseImageUrl="~/dc.gif"></asp:TreeView>


CollapselmageUrl 속성은 하위 노드를 접었을 경우 보여지는 이미지를 의미합니다. 이 밖에 ExpandImageUrl은 하위 노드를 펼쳤을 경우에, LeafNodeStyle-ImageUrl은 최하위 노드에, NoExpandImageUrl은 펼침이 불가능한 노드에, ParentNodeStyle-ImageUrl은 상위노드에, RootNodeStyle-ImageUrl은 루트노드에 대한 노드이미지를 의미합니다.

 

이와 더불어 ShowLines 속성을 True로 설정하면 각 노드간에 연결선을 보여줄 수 있으며 스마트태그를 사용하면 라인과 노드이미지에 대한 전체적인 디자인을 지정할 수 있습니다.(Line에 관한 스타일은 ShowLines가 True로 되어 있어야 사용이 가능합니다.)

 

 5. 노드 선택

 

TreeView는 기본적으로 각 항목을 트리형태로 표시하는 걸로 끝내지만 CheckBox처럼 각 항목에 선택가능한 기능을 부여할 수 있습니다.

 

<asp:XmlDataSource ID="XmlDataSource1" runat="server" DataFile="~/books.xml"></asp:XmlDataSource>
<asp:TreeView ID="TreeView1" runat="server" DataSourceID="XmlDataSource1" ShowCheckBoxes="All">

</asp:TreeView>

 

ShowCheckBoxes 속성은 실제 TreeView에 체크박스를 표시하는데 All값은 모든 노드에, leaf는 최하위 노드에만, None은 없음, Parent는 하위노드가 존재하는 상위노드에만, Root는 최상위 노드에만 체크박스를 적용합니다.

 

사용자가 TreeView의 노드를 선택하고 나면 이를 판단할 수 있는 방법도 있어야 하는데 이 때는 CheckedNodes 속성으로 확인할 수 있습니다.

 

TreeView1.ShowCheckBoxes = TreeNodeTypes.All;

if (TreeView1.CheckedNodes.Count > 0) {

}

 

다만 이것은 선택된 항목이 있는가를 판단하는 것이고 실제 선택된 노드의 요소를 가져오려면 foreach구문을 통해 순회처리를 하면 됩니다.

 

string msg = string.Empty;
foreach (TreeNode tn in TreeView1.CheckedNodes) {
    msg = tn.Text + "가 선택됨";
}

 

 6. 노드 조작

 

TreeView의 노드를 조작하는 작업의 대부분은 프로그램 구현을 통해 이루어 지게 됩니다. 우선 간단하게 다음 메소드를 호출하여 TreeView의 노드를 펼치거나 닫아보겠습니다.

 

TreeView1.ExpandAll();
TreeView1.CollapseAll();

 

페이지가 로드될때 위와 같은 작업을 하고자 한다면 Page_Load안에 넣어서는 안되고 DataBound 이벤트를 선언하여 해당 이벤트 처리기 안에 위 코드를 넣어야 합니다.

 

<asp:TreeView ID="TreeView1" runat="server" DataSourceID="XmlDataSource1" ShowCheckBoxes="All" 

ShowLines="True" OnDataBound="TreeView1_DataBound"></asp:TreeView>

protected void TreeView1_DataBound(object sender, EventArgs e)
{
    TreeView1.CollapseAll();
}

 

만약 특정노트만을 접거나 펼치려면 원하는 해당 노드에 직접적으로 펼침이나 접음메소드를 호출하면 됩니다.

 

<asp:TreeView ID="TreeView1" runat="server" DataSourceID="XmlDataSource1" ShowCheckBoxes="All" 

ShowLines="True" OnDataBound="TreeView1_DataBound">
    <DataBindings>
        <asp:TreeNodeBinding DataMember="catalog" Text="서적관리" />
        <asp:TreeNodeBinding DataMember="book" TextField="id" />
    </DataBindings>
</asp:TreeView>

 

protected void TreeView1_DataBound(object sender, EventArgs e)
{
    TreeView1.CollapseAll();
    TreeView1.FindNode("서적관리").Expand(); //또는 Expanded = true; 로 해도 같음
    TreeView1.FindNode("서적관리/bk102").Expand();
}

 

처리 순서는 먼저 모든 노드를 접은다음 가장 루트노드(서적관리)노드를 펼치고 그 하위에 bk102노드를 펼치도록 합니다. 이때 각 노드의 경로는 '/' 문자로 구분합니다.

 

노드 조작에는 위와 같이 접거나 펼치는것 이외에도 필요에 따라 특정 노드를 추가하거나 삭제해야 하는 경우도 있습니다.

 

우선 노드를 추가하는 것에 대해 알아보자면 TreeNode의 객체를 생성하고 해당 노드에 대한 필요한 속성을 처리한 다음 원하는 위치에 추가하는 순서로 진행됩니다.

 

<asp:Button ID="Button1" runat="server" Text="노드추가" OnClick="Button1_Click" />

protected void Button1_Click(object sender, EventArgs e)
{
    TreeNode tn = new TreeNode();

    tn.Text = "추가된노드";

    TreeView1.Nodes[0].ChildNodes[1].ChildNodes.Add(tn);
}

 

보시는 바와 같이 Nodes나 하위 노드를 지정하는 ChildNodes를 통해서도 노드를 선택할 수 있으며 선택된 노드에 대해 Add메소드를 호출하여 노드를 추가하고 있습니다. 하지만 오해하지 마십시오. TreeView의 노드를 추가하거나 삭제한다 해도 TreeView와 연결된 소스를 변경되지 않습니다.

 

TreeNode tn = TreeView1.FindNode("서적관리/bk102");
TreeView1.Nodes[0].ChildNodes.Remove(tn);

 

위 예제는 검색된 노드를 삭제합니다.

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] 웹서비스(Web Service)  (0) 2016.09.27
[ASP.NET] URL 매핑 (URL 라우팅)  (0) 2016.09.21
[ASP.NET] TreeView  (0) 2016.09.13
[ASP.NET] WCF - 2  (0) 2016.09.07
[ASP.NET] WCF - 1  (0) 2016.08.31
[C#] Stream  (0) 2016.08.24
0 0
Programming/.NET
ListView 는 .NET Framework 3.5 이상부터 추가된 새로운 템플릿 컨트롤중 하나로서 레이아웃이나 기타 작업을 위한 꽤 다양한 옵션을 제공합니다. 해당 옵션은 마법사를 통해 쉽게 적용이 가능합니다.

GridView 는 데이터를 다루는데 필요한 대부분의 기능을 가진 강력한 컨트롤이지만 이 컨트롤이 HTML 로 렌더링되어 표시될때는 꽤 많은 양의 마크업코드와 디자인및 레이아웃을 잡기 위한 추가적인 CSS 설정은 페이지 무겁게 하는 요인이 되었습니다.

과거에는 이를 대체하기 위한 수단으로 DataList 나 Repeater 컨트롤을 사용했는데 GridView 에 비해 가벼워서 좋았지만 이들은 페이징이나 정렬은 물론이고 데이터를 편집하기 위한 기능이 빠져있었기에 개발자가 임의로 만들어야 하는 수고가 필요했습니다.

여기서 ListView 컨트롤은 GridView와 다른 데이터 컨트롤의 사이를 메우기 위한 훌륭한 대체수단이 될 수 있습니다. ListView 는 안에서는 데이터를 추가/수정/편집하기 위한 기능을 제공하면서도 겉으로는 데이터를 표시하기 위해 자체적으로 생성하는 요소를 가지고 있지 않습니다. 이러한 기능은 ListView 내부에 정의하는 템플릿에 의존하며 이 템플릿을 구현하는 종류에 따라 생성되는 HTML 코드가 달라지게 되는 것입니다.

 ListView

ListView 컨트롤을 디자인배치하고 DataSource 를 설정하고 나면 다른 데이터 컨트롤처럼 화면상에 나타나는 레이아웃 형태가 즉시 Design-Time 에 반영되지 않습니다. 왜냐하면 ListView 는 기본적으로 정의된 레이아웃 형태가 존재하지 않으며 LayoutTemplate 과 ItemTemplate 요소 등으로 레이아웃 자체를 정의해야 하기 때문입니다.

ListView 의 레이아웃을 정의하기 위한 가장 쉬운 방법은 컨트롤의 smart tag 를 통해 'Configure ListView' 를 선택하여 레이아웃을 구성하는 것입니다.


Configure ListView Dialog 화면에서 Select a Layout 은 전체적인 Layout 화면을 Select a Style 은 각 Row에 대한 개별적인 디자인설정을 의미합니다. 물론 이 화면에서 특정 Layout 과 Style 을 선택했다고 해서 그 상태로 고정되어야 하는 것은 아니고 세부적인 코드의 편집을 통해 원하는 방향으로 변경할 수 있습니다.

또한 필요하다면 Editing, Inserting, Deleting, Paging 등의 설정을 통하여 어떤 형태의 레이아웃을 선택하든지 해당 기능을 부여하는 것이 가능합니다.

원하는 레이아웃과 스타일을 선택하고 나면 <그림 1-1>과 같은 화면을 볼 수 있습니다.

▶ <그림 1-1>

 Templates

ListView 에서 생성할 수 있는 Template 으로는 ItemTemplate, AlternatingItemTemplate, SelectedItemTemplate, InsertItemTemplate, EditItemTemplate,
EmptyDataTemplate, and LayoutTemplate 등이 있으며 각 컨트롤 템플릿의 용도는 <표 1-1>에 정리하였습니다.

 ItemTemplate  각 데이터 아이템항목에 대한 사용자 인터페이스를 지정합니다.
 ItemSeparatorTemplate  각 Row Item 에 대한 개별적인 UI를 지정합니다.
 AlternatingItemTemplate  짝수 Row에 대한 개별적인 UI를 지정합니다.
 SelectedItemTemplate  현재 선택된 Row에 대한 개별적인 UI를 지정합니다.
 InsertItemTemplate  Row Item 에 대한 데이터 추가시 보여질 UI를 지정합니다.
 EditItemTemplate  Row Item 에 대한 데이터 변경시 보여질 UI를 지정합니다.
 EmptyItemTemplate  현재 페이지의 Row에서 더이상 표시할 Item이 없는 경우 보여질 UI를 지정합니다.
 EmptyDataTemplate  보여줄 Data가 없는 경우 대신 표시할 UI를 지정합니다.
 LayoutTemplate  전체적인 레이아웃에 대한 UI를 지정힙니다.
 GroupTemplate  각 Group 에 대한 UI를 지정합니다.
 GroupSeparatorTemplate  각 Group 사이의 UI를 지정합니다.

특히 LayoutTemplate 과 ItemTemplate 이 중요한데 이 둘은 ListView 컨트롤이 레이아웃을 나타내기 위한 최소한의 구성요소입니다. 여기서 LayoutTemplate 은 최상위의 템플릿이며 여기서 데이터를 표시하기 위한 전체 레이아웃이 정의됩니다.
<LayoutTemplate>
    <table runat="server">
        <tr runat="server">
            <td runat="server">
                <table id="itemPlaceholderContainer" runat="server" border="1" style="background-color: #FFFFFF;border-collapse: collapse;border-color: #999999;border-style:none;border-width:1px;font-family: Verdana, Arial, Helvetica, sans-serif;">
                    <tr runat="server" style="background-color:#DCDCDC;color: #000000;">
                        <th runat="server">BusinessEntityID</th>
                        <th runat="server">PhoneNumber</th>
                        <th runat="server">PhoneNumberTypeID</th>
                        <th runat="server">ModifiedDate</th>
                    </tr>
                    <tr id="itemPlaceholder" runat="server">
                    </tr>
                </table>
            </td>
        </tr>
        <tr runat="server">
            <td runat="server" style="text-align: center;background-color: #CCCCCC;font-family: Verdana, Arial, Helvetica, sans-serif;color: #000000;"></td>
        </tr>
    </table>
</LayoutTemplate>
▶ <코드 2-1>

<코드 2-1>은 LayoutTemplate 의 전체적인 마크업코드입니다. 안에는 Table 요소가 있으며 tr 로 Header 부분이 정의되어 있고 몇몇 CSS 구성도 볼 수 있습니다.

LayoutTemplate 이 전체적인 레이아웃을 담당하고 있다면 ItemTemplate 은 실제 Item 항목을 나타내는 개별적인 Row 부분을 담당합니다.
<ItemTemplate>
    <tr style="background-color:#DCDCDC;color: #000000;">
        <td>
            <asp:Label ID="BusinessEntityIDLabel" runat="server" Text='<%# Eval("BusinessEntityID") %>' />
        </td>
        <td>
            <asp:Label ID="PhoneNumberLabel" runat="server" Text='<%# Eval("PhoneNumber") %>' />
        </td>
        <td>
            <asp:Label ID="PhoneNumberTypeIDLabel" runat="server" Text='<%# Eval("PhoneNumberTypeID") %>' />
        </td>
        <td>
            <asp:Label ID="ModifiedDateLabel" runat="server" Text='<%# Eval("ModifiedDate") %>' />
        </td>
    </tr>
</ItemTemplate>
▶ <코드 2-3>

<코드 2-3>을 보면 알 수 있듯이 LayoutTemplate 의 Table 에 들어갈 각각의 tr 이 정의되어 있으며 tr 안에 표시될 데이터 Item 항목이 Eval 을 통해 지정되어 있습니다.

ListView 는 런타임에서 스스로 레이아웃을 위한 어떠한 HTML 마크업도 생성하지 않으며 GridView 에서처럼 자동적인 필드의 생성로직도 포함하지 않습니다. 따라서 <코드 2-3>과 같은 정의된 레이아웃에서는 각 필드의 Item 값을 표시하기 위한 방법으로 기본적인 ASP.NET 의 inline 데이터 바인딩 구문을 사용하며 이 같은 방법은 ListView 의 모든 템플릿에도 적용됩니다.



ListView 컨트롤은 실행과정에서 스스로 렌더링될때 LayoutTemplate 안에 Item Container 가 정의되어 있음을 기대하고 'itemPlaceholderContainer' 와 같은 형식의 id 값을 갖는 요소를 찾게 됩니다. 그리고 하위의 'itemPlaceholder' 요소 안에 ItemTemplate 의 요소를 삽입하여 최종적인 화면을 구성합니다.(ItemTemplate 뿐만 아니라 AlternatingItemTemplate, EditItemTemplate, EmptyDataTemplate, InsertItemTemplate, SelectedItemTemplate 등도 마찬가지)

 Grouping

ListView 는 각각의 Item 이 렌더링될때 Group 별로 Item 을 표시할 수 있는 GroupTemplate 을 지원합니다.

ListView 의 Item 을 그룹화 하려면 우선 각 Item 을 몇개의 Group 으로 나눌것인지를 지정해야 하며 이것은 ListView 의 GroupItemCount 속성을 통해 설정합니다.
<asp:ListView ID="ListView1" runat="server" DataSourceID="SqlDataSource1" DataKeyNames="BusinessEntityID,PhoneNumber,PhoneNumberTypeID" GroupItemCount="2">
그 다음으로 GroupTemplate 을 추가해 Grouping 될때 보여질 레이아웃을 정의합니다. GroupTemplate 은 LayoutTemplate 안에서 정의된 itemPlaceholderContainer ID 의 table 요소를 GroupItemCount 에서 지정된 수만큼 나누어 담고 화면에 렌더링하는 역활을 수행합니다.
<GroupTemplate>
    <tr runat="server">
        <td runat="server" id="itemContainer" />
    </tr>
</GroupTemplate>
위에서 정의한 GroupTemplate 안에 itemContainer ID 를 갖는 td 가 실제 Item 요소인 ItemTemplate 이 들어갈 부분이며 이것은 ListVIew 컨트롤의 ItemPlaceholderID 를 통해 설정됩니다.

또한 실제 나누어질 각 Group 의 기준은 LayoutTemplate 의 itemPlaceholderContainer ID 를 갖는 table 에 해당하므로 ListView 컨트롤에 이러한 사실을 알리기 위하여 GroupPlaceholderID 속성값을 itemPlaceholderContainer 값으로 지정하면 됩니다.
<asp:ListView ID="ListView1" runat="server" DataSourceID="SqlDataSource1" DataKeyNames="BusinessEntityID,PhoneNumber,PhoneNumberTypeID" GroupItemCount="2" GroupPlaceholderID="itemPlaceholderContainer" ItemPlaceholderID="itemContainer">
이것으로 ListView를 Group 화할 준비가 다 되었습니다. 추가적으로 Item 이 그룹으로 나뉘어져 있음을 눈으로 확인하기 위해 GroupSeparatorTemplate 요소를 추가하여 구분자를 생성하도록 합니다.
<GroupSeparatorTemplate>
    <tr runat="server">
        <td colspan="3"><hr /></td>
    </tr>
</GroupSeparatorTemplate>


ListView 를 Grouping 할때 한가지 주의할점은 데이터가 GroupItemCount 에 지정한 Group 수만큼 나누어 지지 않고 비어있는 부분이 생길수가 있다는 것입니다.


GroupItemCount 를 3으로 지정했는데 정작 Item 수는 4개뿐이라 마지막 2개 부분이 비어있는채로 표시되었습니다. 대부분의 경우 이것은 데이터가 없는 경우이므로 무시하면 되지만 경우에 따라 Table 의 레이아웃 문제로 인해 전체 레이아웃이 깨지는 경우가 생길 수 있으므로 이때는 어떻게 해서든 빈 부분을 임의로 채워줘야 합니다.
<EmptyItemTemplate>
    <tr runat="server">
        <td colspan="5">NO DATA</td>
    </tr>
</EmptyItemTemplate>
이런 경우 EmptyItemTemplate 을 사용할 수 있으며 비어있는 부분을 이 템플릿에 정의된 내용으로 대체할 수 있게됩니다.


 Command

ListView 는 기본적으로 데이터의 편집을 위한 EditItemTemplate, InsertItemTemplate 등의 템플릿을 포함하고 있습니다. 데이터 편집기능이 필요없다면 이들 템플릿은 삭제해도 되지만 여기서 주목해야 할 부분은 각 템플릿에 사용되는 버튼컨트롤입니다.
<EditItemTemplate>
    <tr style="">
        <td>
            <asp:Button ID="UpdateButton" runat="server" CommandName="Update" Text="Update" />
            <asp:Button ID="CancelButton" runat="server" CommandName="Cancel" Text="Cancel" />
        </td>
        <td>
            <asp:Label ID="BusinessEntityIDLabel1" runat="server" Text='<%# Eval("BusinessEntityID") %>' />
        </td>
        <td>
            <asp:Label ID="PhoneNumberLabel1" runat="server" Text='<%# Eval("PhoneNumber") %>' />
        </td>
        <td>
            <asp:Label ID="PhoneNumberTypeIDLabel1" runat="server" Text='<%# Eval("PhoneNumberTypeID") %>' />
        </td>
        <td>
            <asp:TextBox ID="ModifiedDateTextBox" runat="server" Text='<%# Bind("ModifiedDate") %>' />
        </td>
    </tr>
</EditItemTemplate>
<InsertItemTemplate>
    <tr style="">
        <td>
            <asp:Button ID="InsertButton" runat="server" CommandName="Insert" Text="Insert" />
            <asp:Button ID="CancelButton" runat="server" CommandName="Cancel" Text="Clear" />
        </td>
        <td>
            <asp:TextBox ID="BusinessEntityIDTextBox" runat="server" Text='<%# Bind("BusinessEntityID") %>' />
        </td>
        <td>
            <asp:TextBox ID="PhoneNumberTextBox" runat="server" Text='<%# Bind("PhoneNumber") %>' />
        </td>
        <td>
            <asp:TextBox ID="PhoneNumberTypeIDTextBox" runat="server" Text='<%# Bind("PhoneNumberTypeID") %>' />
        </td>
        <td>
            <asp:TextBox ID="ModifiedDateTextBox" runat="server" Text='<%# Bind("ModifiedDate") %>' />
        </td>
    </tr>
</InsertItemTemplate>
이들 컨트롤은 데이터의 편집명령을 수행하기 위한 버튼이며 CommandName 속성을 통해 각 버튼의 역활(동작)을 지정하고 있습니다.

 Paging (DataPager)

DataPager 컨트롤은 IPagableItemContainer 인터페이스를 구현하는 데이터를 바인딩 컨트롤(ListView)에서 사용자에게 순수히 페이징기능을 제공하기 위해 디자인된 컨트롤입니다.

ListView 에서 페이징기능을 제공하려면 DataPager 컨트롤을 사용해야 하는데 Configure ListView 에서 'Enable Paging' 을 체크하거나


직접 Layout Template 에서 DataPager 컨트롤을 추가하면 됩니다.
<asp:DataPager ID="DataPager1" runat="server">
    <Fields>
        <asp:NextPreviousPagerField ButtonType="Button" ShowFirstPageButton="True" ShowLastPageButton="True" />
    </Fields>
</asp:DataPager>
DataPager 는 Fields 요소안에 원하는 형태의 페이징 객체를 담을 수 있으며 예제에서 보이는 객체인 NextPreviousPagerField 는 말 그대로 이전, 다음 형식의 기능을 가진 페이징 기능을 의미합니다.

DataPager 는 이외에도 숫자형식의 페이징을 표시하는 NumericPagerField, 페이징 표시를 직접 커스텀할 수 있는 TemplatePagerField 등을 포함하고 있으며 각각의 Field 는 페이징구현에 필요한 다양한 속성을 포함하고 있습니다. 특히 TemplatePagerField 는 이 객체 스스로 표시할 수 있는 어떠한 내용도 가지고 있지 않지만 임의의 요소를 포함시켜 페이징 인터페이스 자체를 완벽히 디자인할 수 있도록 하고 있습니다.
<Fields>
    <asp:TemplatePagerField>
        <PagerTemplate>
            현재 페이지 <%# Container.TotalRowCount / Container.PageSize %> 중 <%# (Container.StartRowIndex/Container.PageSize) + 1 %> 번째
        </PagerTemplate>
    </asp:TemplatePagerField>
</Fields>
위 예제에서 보여진 Container 객체의 TotalRowCount 나 PageSize 등의 속성에 주목해 주세요. 예제는 단지 현재의 페이지 수를 표시하는데 그치지만 PagerTemplate 안에서 버튼과 같은 컨트롤을 배치하고 클릭등의 이벤트를 정의하여 직접 페이징기능을 구현하려고 할때 페이징 계산시 해당 속성을 활용할 수 있습니다.

DataPager 는 또한 다중 Field 를 정의하거나 하나의 Field 안에서 다수의 페이징 Field 를 포함시켜 사용자에게 여러개의 페이징 기능을 동시에 제공할 수도 있으며 GridView 에서의 페이징기능과는 달리 개별적인 컨트롤로서 분리되어 있기 때문에 LaoutTemplate 안에서 뿐만 아니라 웹폼 어디에서는 위치시킬 수 있습니다.
<form id="form1" runat="server">
    <asp:DataPager ID="DataPager1" runat="server" PagedControlID="ListView1">
        <Fields>
            <asp:TemplatePagerField>
                <PagerTemplate>
                    현재 페이지 <%# Container.TotalRowCount / Container.PageSize %> 중 <%# (Container.StartRowIndex/Container.PageSize) + 1 %> 번째
                </PagerTemplate>
            </asp:TemplatePagerField>
        </Fields>
    </asp:DataPager>
다만 DataPager 가 ListView 의 LaoutTemplate 을 벗어나는 경우 PagedControlID 속성을 통해 어느 컨트롤을 대상으로 페이징을 구현할 것인지를 알려줘야 합니다.
0 0
Programming/.NET
ADO.NET 의 비동기 처리 방법에는 대략적으로 아래와 같은 방법이 존재합니다.

 IAsyncResult 폴딩

이 방법은 비동기 처리를 시작한 이후 처리완료를 전달받기 위해 IAsyncResult 객체를 통해 폴링을 시도하는 방법입니다. 아래 코드를 참고해 주세요.
SqlConnection DBCon = new SqlConnection();
DBCon.ConnectionString = ConfigurationManager.ConnectionStrings["new_connection"].ConnectionString;
            
SqlCommand Command = new SqlCommand();
Command.CommandText = "Select Top 100 * From [Person].[PersonPhone];";
Command.CommandType = CommandType.Text;
Command.Connection = DBCon;
 
DBCon.Open();
 
IAsyncResult ASyncResult = Command.BeginExecuteReader();                
            
while (!ASyncResult.IsCompleted) {
    System.Threading.Thread.Sleep(10000);
}
 
SqlDataReader PhoneReader = Command.EndExecuteReader(ASyncResult);
 
GridView1.DataSource = PhoneReader;
GridView1.DataBind();                
            
DBCon.Close();
위 코드는 PersonPhone 테이블로 부터 상위 100개의 데이터를 가져오는 기능을 수행하는데 SqlCommand 의 객체인 Command 의 BeginExcuteReader() 메소드가 수행되면 프로그램에서 비동기 처리가 시작됩니다. 이 후 처리가 완료될때가지 While 문을 통해 대기하게 되는데 이때 사용된 IAsyncResult 객체의 IsCompleted 속성으로 완료여부를 확인하게 됩니다.
(참고 : 비동기 동작이 제대로 확인되지 않으면 연결문자열에서 Asynchronous Processing=True 구문이 추가되어 있는지 확인해야 합니다.)

참고로 SqlConnection 클래스에는 State 속성을 제공하고 있는데 이 값에 따라 현재 데이터 DB 와의 연결상태를 파악할 수 있습니다.
 
 대기핸들과의 연동

비동기 처리가 시작되고 전체 혹은 일부의 처리가 완료될때 까지 대기하는 대기핸들과의 연동을 시도하는 방법으로서 비동기 처리 방법중 가장 권장되고 있는 방법이기도 합니다. 또한 이 방법은 다중 비동기 처리와 함께 전체 혹은 일부 처리가 동작을 끝낼때 까지 대기할 수 있도록 프로그램을 작성할 수 있을 뿐만 아니라 더 나아가 서로 의존하는 프로세스들을 대기시키고 그외 다른 프로세스는 별도로 처리하는 구현도 가능하게 합니다.

아래 코드는 WaitHandle 클래스의 WaitOne 메소드가 사용된 예제입니다. 이 메소드가 호출되면 비동기 프로세스가 동작을 끝낼때 까지 대기하게 되고 동작을 완료하면(true) 원하는 처리를 수행할 수 있도록 코드를 작성할 수 있습니다..
SqlConnection DBCon = new SqlConnection();
DBCon.ConnectionString = ConfigurationManager.ConnectionStrings["new_connection"].ConnectionString;
            
SqlCommand Command = new SqlCommand();
Command.CommandText = "Select Top 100 * From [Person].[PersonPhone];";
Command.CommandType = CommandType.Text;
Command.Connection = DBCon;
 
DBCon.Open();
 
IAsyncResult ASyncResult = Command.BeginExecuteReader();
System.Threading.WaitHandle WHandle = ASyncResult.AsyncWaitHandle;
 
if (WHandle.WaitOne() == true) {
    SqlDataReader PhoneReader = Command.EndExecuteReader(ASyncResult);
    GridView1.DataSource = PhoneReader;
    GridView1.DataBind();
    DBCon.Close();
}
else {
    
}
else 이하 부분은 비동기 프로세스에 대해 타임아웃등의 문제로 인하여 동작을 제대로 수행하지 못한 경우로서 예외사항을 따로 작성해 두면 됩니다.

단일이 아닌 다중 대기핸들을 사용하는 경우도 크게 다르지 않습니다. 다중 핸들에서 적용할 Command, DataReader 등 쿼리 수행에 필요한 객체등을 각각따로 생성하고 그 만큼 이들 객체에 적용할 대기핸들을 생성해 사용하면 됩니다.
SqlConnection DBCon = new SqlConnection();
DBCon.ConnectionString = ConfigurationManager.ConnectionStrings["new_connection"].ConnectionString;
 
SqlCommand Command1 = new SqlCommand();
Command1.CommandText = "Select Top 100 * From [Person].[PersonPhone];";
Command1.CommandType = CommandType.Text;
Command1.Connection = DBCon;
 
SqlCommand Command2 = new SqlCommand();
Command2.CommandText = "Select Top 10 * From [Person].[PersonPhone];";
Command2.CommandType = CommandType.Text;
Command2.Connection = DBCon;
 
DBCon.Open();
 
IAsyncResult ASyncResult1 = Command1.BeginExecuteReader();
IAsyncResult ASyncResult2 = Command2.BeginExecuteReader();
 
System.Threading.WaitHandle[] WHandles = new System.Threading.WaitHandle[2];
 
System.Threading.WaitHandle top100WHandle = ASyncResult1.AsyncWaitHandle;
System.Threading.WaitHandle top10WHandle = ASyncResult2.AsyncWaitHandle;
 
WHandles[0] = top100WHandle;
WHandles[1] = top10WHandle;
 
System.Threading.WaitHandle.WaitAll(WHandles);
 
SqlDataReader phoneReader1 = Command1.EndExecuteReader(ASyncResult1);
SqlDataReader phoneReader2 = Command2.EndExecuteReader(ASyncResult2);
 
//회수된 데이터의 처리코드
 
DBCon.Close();
다만 데이터베이스에 연결하는 객체는 하나를 사용하는데 이럴 경우 연결문자열에 Multiple Active Result Set (MARS) 을 지원할 수 있도록 MultipleActiveResultSets=True 구문을 추가해야 합니다.

다중 대기핸들을 사용하는 경우 위에서 쓰인 WaitAll 메소드 보다는 WaitAny 메소드를 사용하는 경우가 많은데 WaitAny 메소드는 각각의 비동기 처리가 끝나면 다른 프로세스가 끝날때 까지 대기하는것 없이 바로 해당 프로세스의 처리 결과를 다룰 수 있도록 합니다. 반면 WaitAll 메소드는 배열에 있는 모든 프로세스가 완료되어야 결과를 반환하는 형태의 동작을 수행합니다.
SqlConnection DBCon1 = new SqlConnection();
DBCon1.ConnectionString = ConfigurationManager.ConnectionStrings["new_connection"].ConnectionString;
 
SqlConnection DBCon2 = new SqlConnection();
DBCon2.ConnectionString = ConfigurationManager.ConnectionStrings["new_connection"].ConnectionString;
 
SqlCommand Command1 = new SqlCommand();
Command1.CommandText = "Select Top 100 * From [Person].[PersonPhone];";
Command1.CommandType = CommandType.Text;
Command1.Connection = DBCon1;
 
SqlCommand Command2 = new SqlCommand();
Command2.CommandText = "Select Top 10 * From [Person].[PersonPhone];";
Command2.CommandType = CommandType.Text;
Command2.Connection = DBCon2;
 
DBCon1.Open();
DBCon2.Open();
 
IAsyncResult ASyncResult1 = Command1.BeginExecuteReader();
IAsyncResult ASyncResult2 = Command2.BeginExecuteReader();
 
System.Threading.WaitHandle top100WHandle = ASyncResult1.AsyncWaitHandle;
System.Threading.WaitHandle top10WHandle = ASyncResult2.AsyncWaitHandle;
 
System.Threading.WaitHandle[] Handles = new System.Threading.WaitHandle[] { top100WHandle, top10WHandle };
 
for (int index = 0; index < 2; index++) {
    switch (System.Threading.WaitHandle.WaitAny(Handles)) {
        case 0:
            SqlDataReader phoneReader1 = Command1.EndExecuteReader(ASyncResult1);
            GridView1.DataSource = phoneReader1;
            GridView1.DataBind();
            DBCon1.Close();
            break;
        case 1:
            SqlDataReader phoneReader2 = Command2.EndExecuteReader(ASyncResult2);
            GridView2.DataSource = phoneReader2;
            GridView2.DataBind();
            DBCon2.Close();
            break;
    }
}
위 코드는 WaitAll 대신 WaitAny 메소드를 사용하도록 수정된 예제입니다. WaitAny 메소드는 결과로 정수형의 값을 반환하는데 이 값은 위에서 지정한 대기핸들에 대한 배열의 Index 번호에 해당합니다. 즉, WaitAny는 특정 프로세스가 처리를 완료하면 해당 프로세스에 대한 배열의 Index 값을 반환하고 곧 이 값을 확인하면 현재 완료된 프로세스를 알 수 있게 되는 것입니다.

 CallBack 사용

비동기 프로세스를 시작하는 동안 콜백(callback) 메소드를 사용하는 방법으로서 다른 작업을 병렬적으로 수행할 수 있도록 하며 비동기 프로세스가 종료될때 프로세스를 정리하고 비동기 처리가 종료되면 특정 메소드를 불러 들일 수 있도록 callback 메소드를 호출합니다. 아래 코드를 참고해 주세요.
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Webtest.Default" Async="true" %>
우선 위와 같이 페이지에 Async="true" 항목을 추가설정합니다.
BeginEventHandler _begin = new BeginEventHandler(this._Begin);
EndEventHandler _end = new EndEventHandler(this._End);
AddOnPreRenderCompleteAsync(_begin, _end);
그런다음 비동기 프로세스를 시작하는 메소드(_Begin)와 끝난뒤 호출될 CallBack 메소드(_End)에 대한 이벤트 핸들러를 등록하고 AddOnPreRenderCompleteAsync 메소드를 사용해 Page 의 PreRender 이벤트 단계에서 메소드가 모두 처리될 수 있도록 동기화합니다. 이러한 작업이 필요한 이유는 비동기 특성상 Page Load 가 모두 이루어지고 난 이후에 실제 처리가 완료될 수 있는데 Page 자체에 결과에 대한 표시를 하려는 경우 제대로된 결과를 볼 수 없기 때문입니다.
IAsyncResult _Begin(object sender, EventArgs e, AsyncCallback callback, object state)
{
    SqlConnection DBCon = new SqlConnection();
    DBCon.ConnectionString = ConfigurationManager.ConnectionStrings["new_connection"].ConnectionString;
 
    Command = new SqlCommand();
    Command.CommandText = "Select Top 10 * From [Person].[PersonPhone];";
    Command.CommandType = CommandType.Text;
    Command.Connection = DBCon;
 
    DBCon.Open();
 
    AsyncCallback AsyncResult = new AsyncCallback(_End);
 
    return Command.BeginExecuteReader(callback, state, CommandBehavior.CloseConnection);
}
이제 비동기 처리가 시작될 _Begin 메소드를 위와 같이 작성합니다. 비동기 처리는 BeginExecuteReader 메소드를 호출하면서 시작되며 메소드의 동작이 완료되면 콜백으로 처리가 넘어가게 됩니다.
public void _End(IAsyncResult ar)
{
    SqlDataReader PhoneReader = Command.EndExecuteReader(ar);
 
    GridView1.DataSource = PhoneReader;
    GridView1.DataBind();
}
CallBack 메소드입니다. 메소드에 보이는 Command 객체는 _Begin 메소드에서 사용된 것과 일치하므로 Command 객체는 전역변수로서 선언하도록 합니다.

SqlCommand Command;
 비동기화 처리 취소

비동기처리는 프로그램의 실행흐름과 데이터처리 사이에 동기화를 하지 않고 프로그램실행을 계속 진행해 나갈 수 있다는 장점이 있지만 비동기처리가 예상외로 오래 걸리는 경우 여러가지 문제가 발생할 수 있습니다. 이러한 문제를 해결하기 위해서는 프로그램 최종 사용자나 타임아웃시 Command 객체의 Cancel() 메소드를 호출함으로서 비동기 처리자체를 취소하도록 해야 합니다.

Cancel() 메소드는 어떠한 값도 반환하지 않고 비동기처리 동작을 취소하지만 이미 Command 객체에 의해 실행된 query 동작은 되돌릴 수 없습니다. 때문에 롤백(roll back)과정이 필요한 작업이라면 query 실행전 transaction 을 사용하는등의 조치가 있어야 합니다.

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] 사용자 정의 컨트롤  (0) 2016.07.21
[ASP.NET] 가장 (impersonation)  (0) 2016.07.12
[ASP.NET] ADO.NET 의 비동기 처리  (0) 2016.07.05
[C#] FtpWebRequest / FtpWebResponse  (0) 2016.06.29
[ASP.NET] SqlDataAdapter  (0) 2016.06.14
[C#] FileInfo  (1) 2016.06.09
0 0
Programming/.NET
SqlDataAdapter 는 비연결형의 DataTable 객체와 물리적인 데이터소스간에 이질적인 부분을 해결하기 위한 클래스로서 이를 위해 SELECT 쿼리를 실행하고 데이터소스로부터 결과집합을 DataTable 객체로 복사하거나 INSERT, UPDATE, DELETE 구문을 실행하고 입력데이터를 DataTable 객체에서 추출하는 양방향통신을 수행합니다.

SqlDataAdapter 클래스가 제공하는 주요속성에는 다음과 같은 것들이 있습니다.

 SelectCommand  SqlCommand 형의 값을 읽고쓰는 속성으로서 결과집합에서 DataTable 을 채우기 위해 수행되는 명령을 설정합니다.
 InsertCommand  SqlCommand 형의 값을 읽고쓰는 속성으로서 데이터소스서버에 새로운 데이터를 저장하기 위해 수행되는 명령을 설정합니다.
 DeleteCommand  SqlCommand 형의 값을 읽고쓰는 속성으로서 데이터소스서버에서 특정 데이터를 삭제하기 위한 명령을 설정합니다.
 UpdateCommand  SqlCommand 형의 값을 읽고쓰는 속성으로서 데이터소스서버에서 이미존재하는 데이터를 변경하기 위한 명령을 설정합니다.

참고로 SqlDataAdapter 클래스는 Fill 메소드를 제공하는데 이 메소드는 SelectCommand 속성에 설정된 SQL 구문을 실행하여 결과집합을 수신받고 이것을 DataTable 객체로 복사하는 동작을 자동적으로 수행합니다.
SqlConnection MyConnection = new SqlConnection();
 
MyConnection.ConnectionString = ConfigurationManager.ConnectionStrings["new_connection"].ConnectionString;
            
SqlCommand MyCommand = new SqlCommand();
MyCommand.CommandText = "Select Top 100 * From [Person].[PersonPhone];";
MyCommand.CommandType = CommandType.Text;
MyCommand.Connection = MyConnection;
 
SqlDataAdapter MyAdapter = new SqlDataAdapter();
MyAdapter.SelectCommand = MyCommand;
            
DataTable MyTable = new DataTable();
MyAdapter.Fill(MyTable);
GridView.DataSource = MyTable.DefaultView;
GridView.DataBind();
 
MyCommand.Connection.Open();
 
MyAdapter.Dispose();
MyCommand.Dispose();
MyConnection.Dispose();
위 코드에서는 MyAdapter 클래스의 SelectCommand 속성에 SELECT 구문이 저장된 MyCommand 객체를 지정하고 Fill 메소드를 호출하여 MyTable 이라는 이름의 DataTable 에 결과집합을 저장하는 방법을 보여주고 있습니다. 이렇게 채워진 데이터는 GridView 컨트롤의 DataSource 로 지정하고 화면이 표시하도록 합니다.

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] ADO.NET 의 비동기 처리  (0) 2016.07.05
[C#] FtpWebRequest / FtpWebResponse  (0) 2016.06.29
[ASP.NET] SqlDataAdapter  (0) 2016.06.14
[C#] FileInfo  (1) 2016.06.09
[ASP.NET] LoginView  (0) 2016.06.01
[ASP.NET] EntityDataSource  (0) 2016.05.24
0 0
Programming/.NET
EntityDataSource 컨트롤은 ADO.NET Entity Framework 를 사용시 데이터를 다루기 위한 전용의 데이터 컨트롤로서 EDM(Entity Data Model)을 통해 데이터를 다루게 됩니다.

EntityDataSource 컨트롤을 간단히 사용해 보기 위해 우선 데이터의 소스역활을 하는 EDM을 만들어야 합니다. 다만 EDM과 관련된 상세사항은 추후에 자세히 알아보기로 하고 여기서는 그냥 생성방법만을 알아보고자 합니다.

프로젝트에서 EntityDataModel 라는 폴더를 하나 만들고 해당 폴더에 마우스 오른쪽 버튼을 눌러 Add -> New Item 을 선택합니다.


위 화면에서 Data 카테고리를 선택하고 ADO.NET Entity Data Model 항목을 생성합니다. 예제에서는 test.edmx 로 하였습니다.


Generate from database 를 선택하고 Next 버튼을 누릅니다.


연결할 데이터 베이스를 선택하고 Next 버튼을 누릅니다. 화면상에 AdventureWorks2012ConnectionString 은 프로젝트의 Web.config 파일에 존재하는 데이터베이스 연결 설정입니다. Web.config 파일에 DB연결 관련 설정이 존재하지 않고 아무것도 선택할 수 없으면 New Connection 을 눌러 새로운 연결설정을 구성하도록 합니다.


EDM 안에 생성할 Entity 를 선택합니다. Entity는 프로시저(Procedure)나 테이블(Table)등이 올 수 있습니다. 선택이 완료되면 Finish 를 눌러 설정을 마칩니다.


지금까지의 과정을 거치고 나면 프로젝트에 edmx 파일이 생성되며 더불어 Web.Config 파일도 관련 내용이 추가됩니다.

EDM 을 생성하였으므로 이제 EDM과 EntityDataSource 컨트롤을 연결해 보겠습니다. 우선 아래와 같이 EntityDataSource 컨트롤을 WebForm 에 추가하고 스마트태그를 통해 설정마법사를 호출합니다.


▶ <그림 1-1>

그림 1-1 설정화면에서 Named Connection 부분을 클릭해 방금전 추가한 EDM 이름을 선택합니다. 다만 이때 다음과 같은 오류가 발생하는 경우


프로젝트에 있는 edmx 파일을 메모장으로 열어


ProviderManifestToken 부분의 2012를 2008로 바꿔주시기 바랍니다. 그리고 난뒤 프로젝트를 다시 빌드하고 그림 1-1 화면에서 생성한 EDM을 선택하면 정상적으로 DefaultContainerName 가 표시될 것입니다.


Named Connection 을 선택하고 Next 버튼을 누르면

▶ <그림 1-2>

생성할 Entity 설정화면을 볼 수 있습니다. EntitySetName 에 EDM 설정시 사용했던 테이블이름을 선택하고 Choose the properties in the query result 의 항목을 통해 어떤 항목을 표시할지 지정합니다. 이 때 데이터를 특정 타입으로서 반환되도록 하고 싶다면 EntityTypeFilter 를 통해 타입으로 반환될 항목을 선택합니다.

EntityDataSource 컨트롤은 예를 들어 데이터 컨트롤에 바인딩되어 해당 컨트롤에서 데이터가 추가되거나 변경, 삭제되는 경우에 자동적으로 데이터에 대한 Insert, Update, Delete 가 수행될 수 있습니다. 이런 처리를 설정하고자 한다면 필요한 Enable 항목을 체크하십시오. 다만 이 기능을 이용하려면 Choose the properties in the query result 에서 Select All (Entity Value) 항목만이 체크된 상태여야 합니다.

마지막으로 Finish 를 누르면 모든 설정과정이 완료되며 데이터 컨트롤에 바인딩할 수 있는 준비가 이루어 집니다. <코드 1-1>은 EntityDataSource 를 GridView 데이터 컨트롤에 바인딩한 예제를 보여주고 있습니다.
<form id="form1" runat="server">
<div>
    <asp:EntityDataSource ID="EntityDataSource1" runat="server" ConnectionString="name=AdventureWorks2012Entities" DefaultContainerName="AdventureWorks2012Entities" EnableFlattening="False" EntitySetName="Product" Select="it.[ProductID], it.[Name], it.[ProductNumber]"></asp:EntityDataSource>
    <asp:GridView ID="GridView1" runat="server" DataSourceID="EntityDataSource1"></asp:GridView>
</div>
</form>
참고로 컨트롤의 Select 속성을 통하여 ProductID, Name, ProductNumber 이 세가지 Column 이 표시되도록 하였는데 다른 형태의 Select 구문이 필요한 상황이라면 CommandText 속성을 사용하여 다음과 같이 임의의 쿼리를 지정하여 사용하면 됩니다.
<asp:EntityDataSource ID="EntityDataSource1" runat="server" ConnectionString="name=AdventureWorks2012Entities" DefaultContainerName="AdventureWorks2012Entities" EnableFlattening="False" CommandText="Select P.ProductID, P.[Name], P.[ProductNumber], P.MakeFlag From Product As P" ></asp:EntityDataSource>
이때 필요하다면 Where 나 Group By 절등을 포함하여 표시할 데이터의 범위를 한정할 수 도 있습니다. 다만 CommandText 속성은 Select 와 EntitySetName 속성과는 함께 사용될 수 없습니다. 또한 CommandText 나 GroupBy 속성은 <그림 1-2> 에서 특정 컬럼을 선택하는 것과 같은 조치이므로 automatic inserts, automatic update, automatic delete 설정이 완료 되어 있다 하더라도 해당 설정은 무시됩니다.

마지막으로 EntityDataSource 컨트롤도 다른 데이터 컨트롤과 마찬가지로 WhereParameter, SelectParameter, InsertParameter 나 그외 ControlParameter, QueryStringParameter 등으로 Query에 Parameter 추가가 가능합니다.

'Programming > .NET' 카테고리의 다른 글

[C#] FileInfo  (1) 2016.06.09
[ASP.NET] LoginView  (0) 2016.06.01
[ASP.NET] EntityDataSource  (0) 2016.05.24
[C#] System.IO.Path 클래스  (0) 2016.05.17
[ASP.NET] 예외처리  (0) 2016.05.11
[ASP.NET] 사이트 네비게이션 (sitemap)  (0) 2016.04.19
0 0
Programming/.NET

 1. Menu

 

Menu 컨트롤은 계층화된 데이터구조를 표현하는데 사용되는 컨트롤입니다. 때문에 TreeView 의 데이터소스로는 XmlDataSource 나 SiteMapDataSource 컨트롤(IHierarchicalDataSource 인터페이스를 상속받는)만이 사용될 수 있습니다.

 

 2. SiteMap 연동

 

프로젝트에 존재하는 sitemap 파일을 menu와 연동하려면 먼저 sitemap데이터를 연결짓는 SiteMapDataSource 컨트롤을 배치하고 menu의 DataSourceID에 해당 Data컨트롤의 ID를 지정하면 됩니다.

 

<asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server" />
<asp:Menu ID="Menu1" runat="server" DataSourceID="SiteMapDataSource1"></asp:Menu>

 

참고로 SiteMapDataSource 는 해당 프로젝트에 Web.sitemap 과 같은 사이트맵 파일이 존재해야 합니다.

 

 

 

위 예제는 SiteMapDataSource 컨트롤과 Menu컨트롤을 매핑한 결과입니다.

 

 3. XML 연동

 

XML은 XML파일을 바인딩하는 XmlDataSource 컨트롤을 통해서 연동이 가능합니다. 우선 다음글에서와 같은 내용의 books.xml파일을 생성하고

 

2016/01/18 - [Programming/ASP.NET] - [ASP.NET] XML - 1

 

XmlDataSource 컨트롤로 해당 XML파일을 연결해 보겠습니다.

 

<asp:XmlDataSource ID="XmlDataSource1" runat="server" DataFile="~/books.xml">

</asp:XmlDataSource>

 

그리고 Menu의 DataSourceID를 XmlDataSource의 ID값으로 설정하면 XML내용이 완벽히 바인딩됩니다.

 

 

하지만 경우에 따라 바인딩되는 요소를 제어하고 싶은 경우가 있는데 그럴때는 Menu의 하위 요소인 DataBindings 요소를 사용하면 됩니다.

 

<asp:XmlDataSource ID="XmlDataSource1" runat="server" DataFile="~/books.xml"></asp:XmlDataSource>
<asp:Menu ID="Menu1" runat="server" DataSourceID="XmlDataSource1">
    <DataBindings>
        <asp:MenuItemBinding DataMember="catalog" Text="서적관리" />
        <asp:MenuItemBinding DataMember="book" TextField="id" />
        <asp:MenuItemBinding DataMember="author" TextField="#InnerText" />
    </DataBindings>
</asp:Menu>

 

MenuItemBinding 요소는 XML의 요소와 1:1로 매핑되며 DataMember 속성으로 실제 매핑될 XML요소를 지정합니다. Text 속성은 XML요소의 내용과는 상관없이 원하는 문자열을 표시하지만 TextField속성을 사용하여 XML요소의 속성을 지정하면 해당 속성값이 문자열로 표시됩니다. 예제에서의 두번째 TextField에는 #InnerText 가 지정되었는데 이것은 속성이 아닌 XML내부의 문자열을 가져오겠다는 의미입니다.

 

 4. 내장 스타일

 

Visual Studio의 디자인 모드에서 스마트태그를 선택하면 다음과 같이 자체지원하는 스타일을 적용할 수 있습니다.

 

 

특정 스타일을 적용한뒤 aspx의 디자인페이지 소스를 보면 다음과 같은 내용이 들어가 있음을 알 수 있습니다.

 

<asp:Menu ID="Menu1" runat="server" DataSourceID="XmlDataSource1" BackColor="#FFFBD6" DynamicHorizontalOffset="2" Font-Names="Verdana" Font-Size="0.8em" ForeColor="#990000" StaticSubMenuIndent="10px">
    <DynamicHoverStyle BackColor="#990000" ForeColor="White" />
    <DynamicMenuItemStyle HorizontalPadding="5px" VerticalPadding="2px" />
    <DynamicMenuStyle BackColor="#FFFBD6" />
    <DynamicSelectedStyle BackColor="#FFCC66" />
    <StaticHoverStyle BackColor="#990000" ForeColor="White" />
    <StaticMenuItemStyle HorizontalPadding="5px" VerticalPadding="2px" />
    <StaticSelectedStyle BackColor="#FFCC66" />
</asp:Menu>

 

여기서는 주목해야할 부분이 Menu내부의 요소들인데 Dynamic은 동적항목으로서 특정 메뉴에 마우스를 올려 나타나는 메뉴부분을 의미하며 Static은 정적항목으로 처음부터 존재하는 메뉴를 의미합니다. 예제에서는 catalog가 Static, 그 하위에 나타나는 것을 Dynamic으로 분류할 수 있습니다.

 

뒤이어 나오는 HoverStyle은 마우스를 올린경우의 스타일을, MenuItemStyle은 마우스를 올리지 않은 경우, MenuStyle은 전체적인 메뉴 스타일을 지정하며 SelectedStyle은 해당 메뉴항목을 선택했을때의 스타일을 의미합니다.

 

이 밖에 Menu항목에 화살표문자대신 이미지를 대신 보여주기 위한 동적항목 DynamicPopOoutImageUrl과 정적항목 StaticPopOutImageUrl 속성이 있고 -SeparatorImageUrl 속성으로 각 메뉴에 대한 구분이미지를 지정할 수도 있습니다. -SeparatorImageUrl에서 -부분에는 DynamicBottom과 같은 단어로 시작할 수 있는데 Dynamic은 동적항목을 Static은 정적항목을 의미하고 Bottom이나 Top을 구별해 위치에 맞는 이미지를 지정하도록 합니다.

 

또한 메뉴레이아웃 변경을 위한 Orientation도 자주 사용되는 속성중의 하나입니다.

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] 공급자 모델 - 2  (0) 2016.03.22
[ASP.NET] 공급자 모델 - 1  (0) 2016.03.17
[ASP.NET] Menu  (0) 2016.03.10
[ASP.NET] Calender  (0) 2016.03.07
[ASP.NET] DataList  (0) 2016.03.03
[ASP.NET] XML - 6  (0) 2016.02.23
0 0
Programming/.NET

Calender 는 웹에 달력기능을 제공하는 컨트롤입니다.
<asp:Calendar ID="Calendar1" runat="server"></asp:Calendar>
 주요속성/이벤트

1. SelectedDate

Calender에서 선택한 날짜값을 DateTime 객체로 가져옵니다.

2. SelectedDates

SelectedDate와 기능은 같지만 Calender에서 주나 월에 대한 날짜를 선택하는 경우 해당 날짜범위를 모두 가져오도록 하는 속성입니다.
protected void Calendar1_SelectionChanged(object sender, EventArgs e)
{
    for (int day = 0; day < Calendar1.SelectedDates.Count; day++)
        Response.Write(Calendar1.SelectedDates[day].ToShortDateString());
}
3. SelectionMode

SelectionMode를 지정하면 Calender에서 날짜를 선택하는 방식을 바꿀 수 있습니다. Day는 날짜만을, DayWeek는 날짜와 주를 선택할 수 있으며 DayWeekMonth는 날짜, 주와 함께 월(요일을 나타내는 부분 왼쪽에 표시)을 선택할 수 있도록 합니다.

만약 속성의 값을 None으로 지정하면 아무것도 선택할 수 없게 됩니다.

4. OnSelectionChanged

Calender 에서 특정 날짜를 선택하는 경우 발생하는 이벤트입니다.

5. OnDayRender

Calender에서 날짜를 표시할때의 이벤트입니다. 이 이벤트를 잘 활용하면 Calender에서 표시하는 내용을 원하는 형태로 바꿀 수 있습니다. 아래 예제는 특정 날짜가 확인되면 날짜대신 원하는 내용을 표시하는 방법입니다.
protected void Calendar1_DayRender(object sender, DayRenderEventArgs e)
{
    if (e.Day.Date.Month == 1 && e.Day.DayNumberText == "1")
        e.Cell.Text = "내 생일";
}

▶  1월 1일인 경우 해당 날짜에 '내 생일' 표시

혹은 특정 컨트롤을 대신해서 표시한다거나 날짜를 표시하는 Cell 자체의 디자인을 새롭게 구성할 수 있습니다.
if (e.Day.Date.Month == 1 && e.Day.DayNumberText == "13") {
    Image img = new Image();
    img.ImageUrl = "~/images/12_mon.gif";
    e.Cell.Controls.Add(img);

    e.Cell.BackColor = System.Drawing.Color.Red;
    e.Cell.BorderColor = System.Drawing.Color.Blue;
    e.Cell.BorderStyle = BorderStyle.Double;
    e.Cell.BorderWidth = 30;
}
참고로 Cell은 날짜를 표시하는 박스 자체이며 Day는 박스안에서 표시되는 날짜의 영역을 의미합니다. 각 영역에는 지정가능한 많은 속성이 있으며 필요에 따라 사용할 수 있는 유연성을 제공합니다.

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] 공급자 모델 - 1  (0) 2016.03.17
[ASP.NET] Menu  (0) 2016.03.10
[ASP.NET] Calender  (0) 2016.03.07
[ASP.NET] DataList  (0) 2016.03.03
[ASP.NET] XML - 6  (0) 2016.02.23
[ASP.NET] XML - 5  (0) 2016.02.18
0 0
Programming/.NET
DataList 컨트롤은 템플릿을 통해 레이아웃과 기타 필요기능을 구성하여 데이터를 화면에 표시하는 컨트롤중 하나입니다.

아래는 DataList 컨트롤에서 추가가능한 템플릿입니다.

 AlternatingItemTemplate  전체 Row 에서 각 Row 를 구분하는 레이아웃을 제공하는 템플릿입니다.
 EditItemTemplate  편집상태일때 나타나는 레이아웃을 지정합니다.
 FooterTemplate  마지막 항목에 대한 레이아웃을 지정합니다.
 HeaderTemplate  첫번째 항목에 대한 레이아웃을 지정합니다.
 ItemTemplate  기본적으로 데이터의 각 항목을 표시하는 기본 레이아웃을 지정합니다.
 SelectedItemTemplate  컨트롤에서 특정 항목이 선택된 상태일때를 나타내는 레이아웃을 정의합니다.
 SeparatorTemplate  각 항목의 아이템을 구분하는 레이아웃을 정의합니다.

상기 템플릿의 대부분은 선택항목이지만 최소한 ItemTemplate 은 기본적으로 구현되어야 합니다. 데이터를 표시하기 위한 가장 기본적인 템플릿이기 때문입니다.
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:new_connection %>" SelectCommand="SELECT Top 10 * FROM [Person].[PersonPhone]"></asp:SqlDataSource>
<asp:DataList ID="DataList1" runat="server" DataSourceID="SqlDataSource1">
    <ItemTemplate>
        전화번호 : <asp:Label ID="Label1" runat="server" Text='<%# Eval("PhoneNumber"%>' />
    </ItemTemplate>
</asp:DataList>
템플릿 내부는 HTML 요소나 기타 내용을 추가하여 전체적인 디자인을 구성할 수 있습니다. 주목해야 할 부분은 Label 컨트롤 부분인데 데이터 소스로부터 가져온 데이터를 표시하기 위해서 Inline 데이터 바인딩 구문인 Eval 함수를 사용하였습니다.

여기서 ItemTemplate 은 테이블요소를 사용하여 레이아웃을 구성하게 되는데


페이지 디자인구성상 내부요소를 Table 이 아닌 span 요소로 대체하고자 한다면 DataList 의 Repeatlayout 속성을 Flow 로 수정하면 됩니다.

참고로 아래는 ItemTemplate 이외에 AlternatingItemTemplate 등의 다른 템플릿요소를 사용한 예를 보여주고 있습니다.
<asp:DataList ID="DataList1" runat="server" DataSourceID="SqlDataSource1" RepeatLayout="Flow">
    <AlternatingItemTemplate>
        전화번호 : <asp:Label ID="Label1" runat="server" Text='<%# Eval("PhoneNumber"%>' ForeColor="Yellow" />
    </AlternatingItemTemplate>
    <SeparatorTemplate><hr /></SeparatorTemplate>
    <ItemTemplate>
        전화번호 : <asp:Label ID="Label1" runat="server" Text='<%# Eval("PhoneNumber"%>' />
    </ItemTemplate>
</asp:DataList>


위 예제에서 AlternatingItemTemplate 는 ItemTemplate 의 반복요소를 나타내고 있는데 이 템플릿에는 ItemTemplate 과 같은 구성의 내용이 들어가 있음을 볼 수 있습니다. 차이점은 ForeColor 속성을 추가하여 반복적으로 다른 색상이 표시되도록 했다는 것인데 복잡한 요소보다는 색상에 의한 구분처럼 단순한 기능이 필요하다면 AlternatingItemTemplate 보다 AlternatingItemStyle 사용을 권장합니다.

AlternatingItemStyle 은 구분이 필요한 속성만을 추가하여 좀더 간단하고 쉽게 원하는 결과를 이끌어 낼 수 있도록 하지만 문자열, HTML 요소와 같은 정적/동적컨텐츠 삽입은 불가능합니다.

DataList 컨트롤에서는 RepeatColumns 라는 속성도 주목할 필요가 있습니다. DataList 는 본래 하나의 컬럼만을 표시하지만 RepeatColumns 속성을 설정하면 원하는 만큼의 컬럼(Column, 열)을 생성하여 데이터를 화면에 표시할 수 있습니다.
<asp:DataList ID="DataList1" runat="server" DataSourceID="SqlDataSource1" RepeatColumns="2">
    <ItemTemplate>
        전화번호 : <asp:Label ID="Label1" runat="server" Text='<%# Eval("PhoneNumber"%>' />
    </ItemTemplate>
</asp:DataList>
다중 열을 생성하고 데이터를 화면에 표시하면 표시순서가 왼쪽 위에서 아래 순서로 흘러가는것을 볼 수 있는데 이 규칙을 깨려면 RepeatDirection 속성을 사용하면 됩니다. 기본값은 Vertical 이며 horizontal 로 바꾸면 왼쪽 위에서 오른쪽 순으로 표시할 항목이 배열됩니다.

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] Menu  (0) 2016.03.10
[ASP.NET] Calender  (0) 2016.03.07
[ASP.NET] DataList  (0) 2016.03.03
[ASP.NET] XML - 6  (0) 2016.02.23
[ASP.NET] XML - 5  (0) 2016.02.18
[ASP.NET] XML - 4  (0) 2016.02.11
0 0
Programming/.NET

 

 1. NameTable

 

NameTable은 XML요소를 개체참조형식으로 담아두는데 사용됩니다. 예를 들어 XML데이터를 순회하면서 다음과 같이 특정 요소를 문자열로 비교해서 처리해야 하는 경우라면

 

if (reader.NodeType == XmlNodeType.Element && reader.LocalName.Trim() == "title") {

 대신 NameTable 클래스를 사용하여 비교자체를 개체참조 형태로 대신할 수 있습니다. 이것은 단순히 문자열을 비교하는 것보다 일정이상 성능향상을 기대할 수 있게 합니다.

 

string xml_file = Server.MapPath("books.xml");
string xml_schema = Server.MapPath("books.xsd");

XmlReaderSettings xrs = new XmlReaderSettings();
xrs.IgnoreComments = true;
xrs.IgnoreWhitespace = true;

xrs.Schemas.Add(null, xml_schema);
xrs.ValidationType = ValidationType.Schema;
xrs.ValidationFlags = System.Xml.Schema.XmlSchemaValidationFlags.ReportValidationWarnings;
xrs.ValidationEventHandler += xrs_ValidationEventHandler;

NameTable nt = new NameTable();
object book = nt.Add("title");

xrs.NameTable = nt;

using (XmlReader reader = XmlReader.Create(xml_file, xrs)) {
    while (reader.Read()) {
        if (reader.NodeType == XmlNodeType.Element && book.Equals(reader.LocalName)) {
            while (reader.Read()) {
                if (reader.NodeType == XmlNodeType.Text) {
                    Response.Write(reader.Value + "<br />");
                    break;
                }
            }
        }
    }
}

▶ ex 1-1

 

NameTable 클래스에서 특정 객체를 생성한 다음 Add메소드를 호출하여 XML요소인 title 추가를 시도합니다. Add 메소드는 XML요소의 title과 동일한 title 개체참조를 반환하게 되고 Equals메소드를 통해 두개체의 동일성을 확인하게 되는 것입니다.

 

작은 XML의 경우에는 모르지만 대용량일 수록 성능향상을 기대할 수 있습니다. 게다가 NameTable은 다른 XML개체에서 재사용이 가능합니다.

 

 2. 데이터타입 변환

 

XML을 파싱할때 특정 데이터타입으로 XML요소의 값을 가져와야 하는 경우라면 XmlReader 클래스 개체에서 ReadElementContentAsXXX 형태의 메소드를 사용하면 됩니다. 예를 들어 이전 1-1 예제에서는 XML값을 가져오기 위해 reader.Value 처름 사용했다면 이것을 다음과 같이 바꿀 수도 있습니다.

 

Response.Write(reader.ReadElementContentAsString() + "<br />");

예제는 값을 String 테이터타입 형식으로 가져오지만 만일 정수나 기타 숫자를 통해 합계등을 구해야 하는 경우라고 가정할때

 

int.Parse(reader.Value)

기존에 위와 같이 형변환등을 수행했다면 대신 ReadElementContentAsInt() 메소드로 정수형태의 값을 가져오는 것입니다.

 

int i = reader.ReadElementContentAsInt()

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] XML - 4  (0) 2016.02.11
[ASP.NET] XML - 3  (0) 2016.02.01
[ASP.NET] XML - 2  (0) 2016.01.26
[ASP.NET] XML - 1  (0) 2016.01.18
[ASP.NET] Command Object  (0) 2016.01.13
[ASP.NET] DLL 교체 시 웹서비스 지연현상  (0) 2015.08.07
0 0
Programming/.NET
Command 객체는 Connection 객체를 통해 연결된 DB 데이터를 다루기 위해 쿼리 또는 저장프로시저등과 같은 명령를 실행하는데 사용됩니다. 예를 들어 특정 데이터를 얻기 위한 Select 등의 쿼리는 그 결과로 DataSet 이나 DataReader 객체등의 형식과 같은 결과집합을 얻게 합니다.

Command 객체에서 주로 사용되는 속성은 다음과 같습니다.

 CommandText  일반적인 쿼리나 저장프로시저호출등의 실질적인 쿼리구문을 설정합니다.
 CommandTimeout  CommandText 에 설정된 쿼리를 실행하는데 필요한 대기시간(초)을 설정합니다. 해당 시간동안 DB서버로 부터 응답을 얻지 못하면 명령실행은 중지되며 예외를 발생시키게 됩니다. 기본값은 30초입니다.
 CommandType  CommandText 에 설정된 쿼리의 유형을 나타내거나 설정합니다.
 Connection  해당 Command 객체에 사용되는 Connection 객체를 설정합니다.

Command 객체는 실행하는 쿼리의 특성에 따라 여러 처리방법을 가지고 있으며 다음과 같은 값을 설정할 수 있습니다.

 ExecuteNonQuery  지정된 쿼리를 실행하며 해당 쿼리로 인해 영향을 받은 Row 수를 반환합니다.
 ExecuteReader  지정된 쿼리를 실행하고 그 결과로 ExecuteReader 클래스의 인스턴스를 반환합니다. 주로 Select 쿼리의 결과로 반환되는 데이터집합을 담고 있습니다.
 ExecuteRow  지정된 쿼리를 실행하고 그 결과로 SqlRecord 클래스의 인스턴스를 반환합니다. 쿼리 결과로 나오는 결과집합중 가장 첫행의 Row 값만 받을 경우 사용됩니다.
 ExecuteScalar  지정된 쿼리를 실행하고 그 결과로 Object 클래스의 인스턴스를 반환합니다. 처리결과가 Table 이나 Row 형태가 아닌 특정값 하나를 반환받을 경우 사용됩니다. 좀더 정확히는 첫 Row 의 첫 Column 의 값을 반환하는 것으로 하나 이상의 Column 이나 Row가 있다 하더라도 모두 무시됩니다.
 ExecuteXmlReader  지정된 쿼리를 실행하고 그 결과로 XmlReader 클래스의 인스턴스를 반환합니다. 주로 XML 형식의 결과를 받는데 사용됩니다.

string strCmd = "Update [Person].[PersonPhone] Set PhoneNumber = '000-000-0000' Where BusinessEntityID = 20777;";
 
SqlConnection conn = new SqlConnection(@"Data Source=localhost;Initial Catalog=AdventureWorks2012;User ID=sa;Password=123");
SqlCommand cmd = new SqlCommand(strCmd, conn);
conn.Open();
 
int updateRow = cmd.ExecuteNonQuery();
conn.Close();
▶ 예제

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] XML - 2  (0) 2016.01.26
[ASP.NET] XML - 1  (0) 2016.01.18
[ASP.NET] Command Object  (0) 2016.01.13
[ASP.NET] DLL 교체 시 웹서비스 지연현상  (0) 2015.08.07
[ASP.NET] SqlConnection  (0) 2015.05.18
[ASP.NET] IAsyncResult 인터페이스  (0) 2015.04.20
0 0
Programming/.NET
Connection 객체의 주요 목적은 데이터 소스로의 연결정보를 담는것으로 데이터소스의 도메인이나 서버 IP 및 사용자정보(아이디/비밀번호)등을 포함하고 있습니다. 흔히 이런 정보를 연결문자열이라고 부르며 문자열형태로 이루어진 데이터를 의미합니다.

Connection 객체에서 특히 SqlConnection 은 SQL Server 7.0 또는 그 상위의 MS SQL 데이터소스 작업을 위해 존재하는 클래스로서 다음과 같은 몇가지 속성을 포함하고 있습니다. 특히 ConnectionString 속성은 데이터소스 연결을 위해 필수적으로 사용해야 하는 속성입니다.

 ConnectionString  연결문자열을 설정하거나 설정된 값을 읽어옵니다.
 Database  읽기전용이며 연결된 데이터베이스 이름을 반환합니다.
 Datasource  SQL 서버 데이터 베이스의 인스턴스 이름을 반환하는 읽기전용 속성입니다.
 State  현재 연결상태를 반환하며 상태에 따라 Broken, Closed, Connecting, Executing, Fetching, Open 등의 값을 가질 수 있습니다. 읽기전용입니다.

SQL 데이터 베이스 연결을 위해서는 다음과 같은 방법으로 SqlConnection 클래스를 사용합니다.
SqlConnection conn = new SqlConnection(@"Data Source=localhost;Initial Catalog=AdventureWorks2012;User ID=sa;Password=123");
conn.Open();
▶ <코드 1-1>

<코드 1-1>에서는 SqlConnection 클래스에 대한 인스턴스를 생성하고 이와 동시에 연결문자열을 파라메터로 넘겨 초기화 합니다. 여기에서는 localhost 에 위치한 SQL Server 의 로그인을 위해 사용자 아이디와 비밀번호를 지정했는데 윈도우 계정인증을 통해 데이터 베이스에 로그인 하고자 한다면 <코드 1-2>와 같은 형태의 연결문자열을 지정해야 합니다.
@"Data Source=localhost;Initial Catalog=AdventureWorks2012;Integrated Security=True;User Instance=True"
▶ <코드 1-2>

또한 연결문자열에서 Data Source 에는 서버의 도메인이나 IP 를 지정하는 경우가 대부분 이지만 <코드 1-3>과 같이 직접 DB 파일을 지정할 수도 있습니다.
@"Data Source=.\SQLEXPRESS;AttachDbFilename=D:\DATABASE\AdventureWorks2012.MDF;Integrated Security=True;User Instance=True"
▶ <코드 1-3>

코드 1-1 에서 1-3 까지는 연결문자열을 직접 지정했는데 실제로 이렇게 하기보다는 관리성 향상과 더 높은 수준의 보안을 유지할 수 있는 Web.config 파일을 이용하는 경우가 더 많습니다.
<connectionStrings>
  <add name="new_connection" connectionString="Data Source=localhost;Initial Catalog=AdventureWorks2012;User ID=sa;Password=123" providerName="System.Data.SqlClient" />
</connectionStrings>
Web.config 파일 안에서 위와 같이 연결문자열을 지정하고난 뒤 실제 SqlConnection 안에서 Web.config 의 해당 정보를 읽어오려면 다음과 같이 처리할 수 있습니다.

SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["new_connection"].ConnectionString);
▶ <코드 1-4>

참고로 <코드 1-4>를 위해서는 System.Configuration 네임스페이스 선언이 필요합니다.

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] Command Object  (0) 2016.01.13
[ASP.NET] DLL 교체 시 웹서비스 지연현상  (0) 2015.08.07
[ASP.NET] SqlConnection  (0) 2015.05.18
[ASP.NET] IAsyncResult 인터페이스  (0) 2015.04.20
[ASP.NET] LINQ 활용  (0) 2014.10.07
[ASP.NET] DataSet  (0) 2014.10.06
0 0
Programming/.NET
SqlCommand 클래스와 관련한 모든 비동기 메소드는 IAsyncResult 인터페이스 객체를 반환합니다. 아래 표는 IAsyncResult 인터페이스에 대한 대략적 속성입니다.

 AsyncState 읽기 전용으로서 프로세스의 상태를 설명하는 객체를 반환합니다.
 AsyncWaitHandle 읽기 전용으로서 TimeOut 설정및 프로세스 완료여부 확인 그리고 완료를 위해 대기중인 코드를 강제로 종료하는데 사용될 수 있는 WaitHandle 의 인스턴스를 반환합니다.
 CompletedSynchronously 읽기 전용으로서 프로세스가 동기적으로 실행되었는지를 나타내는 부울(Boolean) 형의 값을 반환합니다.
 IsCompleted 읽기 전용으로서 프로세스가 완료되었는지 여부를 나타내는 부울(Booleand) 형의 값을 반환합니다.

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] DLL 교체 시 웹서비스 지연현상  (0) 2015.08.07
[ASP.NET] SqlConnection  (0) 2015.05.18
[ASP.NET] IAsyncResult 인터페이스  (0) 2015.04.20
[ASP.NET] LINQ 활용  (0) 2014.10.07
[ASP.NET] DataSet  (0) 2014.10.06
[ASP.NET] WaitHandle  (0) 2014.10.02
0 0
Programming/.NET
DataSet 클래스는 ADO.NET 에서 가장 핵심 클래스중 하나로서 데이터 소스와의 비연결 상태에서도 데이터를 다룰 수 있게 하는 방안을 제공하고 있습니다. 이는 ADO.NET 1.0 이 처음발표 될때부터 소개된 것으로 지금까지도 계속 발전해 나가고 있습니다.

DataSet 클래스로 부터 생성된 객체는 DataTable 클래스 객체의 컨테이너로서 동작합니다. 여기서 DataTable 객체는 메모리상의 논리적인 테이블을 의미하는 것으로 행, 열은 물론 키, 제약조건이나 다른 DataTable 과의 관계구조까지도 포함됩니다. 데이터 소스의 Table 구조를 그대로 복사해 오는 것과 같은데 심지어 DataSet 은 DataTable 객체의 컨테이너에 해당되므로 두개이상의 DataTable 과의 관계로 구성된 객체를 그대로 포함할 수 있습니다.

이전의 ADO.NET 에서는 DataTable 에 바로 접근하는 방법을 허용하지 않았으며 DataSet 을 통해서만 DataTable 에 접근할 수 있었습니다. 현재는 이 제한이 사라졌으며 다중 DataTable 객체에 대한 관리나 작업이 필요하지 않다면 굳이 성능상 DataSet 사용을 권장하지는 않습니다.

현재 ADO.NET은 DataReader 를 개체로 사용하여 메모리에 DataTable을 로드하는 기능을 제공하며 한번 작성된 데이터 접근 코드를 이용해 DataReader 를 재사용 할 수 있는 유연성을 가지고 있습니다.
SqlConnection MyConnection = new SqlConnection();
 
MyConnection.ConnectionString = ConfigurationManager.ConnectionStrings["new_connection"].ConnectionString;
            
SqlCommand MyCommand = new SqlCommand();
MyCommand.CommandText = "Select Top 100 * From [Person].[PersonPhone]";
MyCommand.CommandType = CommandType.Text;
MyCommand.Connection = MyConnection;
 
MyCommand.Connection.Open();
 
SqlDataReader MyReader = MyCommand.ExecuteReader(CommandBehavior.CloseConnection);
DataTable MyDataTable = new DataTable();
MyDataTable.Load(MyReader);
 
GridView.DataSource = MyDataTable;
GridView.DataBind();
            
MyCommand.Dispose();
MyConnection.Dispose();
▶ 예제 1-1

위 코드에서 DataTable 은 DataReader 를 개체로 하여 데이터를 로드하는 예제를 보여주고 있습니다. 이처럼 DataReader 객체로 부터 DataTable 객체 데이터를 로드할 수 있을 뿐만 아니라 이미 존재하는 DataTable 객체에서 DataTableReader 를 끄집에 내는것도 가능합니다. 단지 DataTable 객체에서 DataTableReader 객체의 인스턴스를 반환하는 DataReader 생성 메소드를 호출하기만 하면 되는것입니다.

ADO 2.6 에서는 대용량 데이터에 명령을 수행하면 여러 행으로 구성된 단일 데이터 집합을 얻을 수 있었으나 현재의 ADO.NET 은 실제 구조를 유지하는 데이터 집합을 반환하기 위해 DataSet 을 사용하기도 합니다. 어떤 경우는 DataSet을 통해 본래 데이터 구조에 대한 복사본을 유지하는 것이 성능상 이점을 제공해 줄 수 있기 때문입니다. 비연결 데이터를 메모리상에 유지하며 특정 Table을 대상으로 작업하거나 Table 간의 관계를 적용시킬 수 있습니다. Table 간의 관계가 명확하게 드러난 채로 작업이 되어야 하는 경우라면 당연히 DataSet을 사용하는 편이 나을 것입니다.

DataSet 은 원본데이터를 비연결상태에서 다루기 위한 복사본이므로 원본하고는 무관하게 원본과 같은 데이터를 다룰 수 있는 이점을 제공하기도 합니다. 이것은 성능상이나 혹은 서버의 부하를 줄일 수 있는 방법이 될 수 있는데 다만 말 그대로 복사본이므로 DataSet 에 데이터의 변경, 삭제, 추가등의 작업을 하여도 개발자 임의로 적용을 시도하지 않는 한 데이터 소스원본에는 영향을 주지 않습니다.

DataSet 을 사용함으로서 얻을 수 있는 또다른 이점은 별도의 데이터 소스에 있는 데이터를 지역적으로 통합하여 다룰 수 있다는 것입니다. 예를 들어서 A 사의 고객정보는 SQL 서버 테이블에 있고 B 사의 고객정보는 Oracle 서버 테이블이 있다고 한다면 이 두 테이블 데이터를 하나의 DataSet 에 담아두고 다루는것도 가능합니다. 게다가 내부 데이터에 대한 대량의 XML 로의 전환이 가능하므로 DataSet 자체를 이해할 수 없는 이기종간의 시스템이나 애플리케이션 사이를 XML을 통하여 쉽게 전송하고 데이터를 통합할 수 있습니다.

아래는 예제 1-1 코드에서 DataSet 을 사용하도록 수정한 예제입니다.
SqlConnection MyConnection = new SqlConnection();
 
MyConnection.ConnectionString = ConfigurationManager.ConnectionStrings["new_connection"].ConnectionString;
            
SqlCommand MyCommand = new SqlCommand();
MyCommand.CommandText = "Select Top 100 * From [Person].[PersonPhone]";
MyCommand.CommandType = CommandType.Text;
MyCommand.Connection = MyConnection;
 
MyCommand.Connection.Open();
 
SqlDataAdapter sda = new SqlDataAdapter(MyCommand);
DataSet ds = new DataSet();
sda.Fill(ds, "phoneTable");
 
GridView.DataSource = ds;
GridView.DataBind();
            
MyCommand.Dispose();
MyConnection.Dispose();
여러 이점이 있기는 하지만 DataSet은 어느상황에서나 최적의 방안을 제공해 주지는 않습니다. 가장 큰 예로 꽤 큰 덩치를 들 수 있는데 이는 앞서 말씀드린 것처럼 단순한 데이터를 벗어나 테이블간의 관계등 원본과 같은 몇몇가지 속성을 DataSet 이 모두 가지고 있기 때문입니다. 이렇게 무거운 DataSet 은 방문자가 ASP.NET Web Form 페이지를 요구할때 마다 데이터 소스의 호출로 인해 페이지가 다시 재생성되는 동작이 반복되며 DataSet 또한 별도로 캐싱처리하지 않는 한 페이지와 마찬가지로 재생성 동작을 거치게 됩니다. 테이블에 관한 여러 정보대신 약간의 데이터만을 다루면 되는 상황이라면 DataSet 보다는 DataReader 클래스를 사용하여 데이터소스의 직접적인 접근을 시도하는 것이 편이 훨씬 나을지도 모릅니다.

DataSet 을 사용함에 있어 오류를 줄이고 좀더 간단한 형태의 접근이 필요하다면 Typed DataSet 을 사용할 수 있습니다. 예를 들어 Typed DataSet 이전에 코드는 아래와 같았습니다.
ds.Tables["phoneTable"].Rows[0]["PhoneNumber"] = "000-000-0000";
다소 극단적이긴 하지만 위 코드는 phoneTable 이라는 이름의 테이블에 첫번째 Row 에서 PhoneNumber 열값을 바꾸는 동작을 수행합니다. 하지만 위 코드가 정확히 수행되려면 반드시 phoneTable 이라는 테이블이 있어야 하며 PhoneNumber 라는 열값이 존재한다는게 보장되어야 합니다. 이름을 지정할때 실수로 한글자라도 틀리게 되면 Application 은 아마 오류를 내뱉을 것입니다.

이런 피곤한 방식을 탈피하기 위해 Typed DataSet 을 사용하려면 우선 프로젝트에 DataSet 을 다음과 같이 추가합니다.


Server Explorer 에서 DataSet 대상이될 위에서 생성한 xsd 위에 끌어다 놓습니다.


예제 1-1 에서 사용한 DataSet 대신 방금 생성한 DataSet 을 객체화 하여 사용합니다.
SqlConnection MyConnection = new SqlConnection();
 
MyConnection.ConnectionString = ConfigurationManager.ConnectionStrings["new_connection"].ConnectionString;
            
SqlCommand MyCommand = new SqlCommand();
MyCommand.CommandText = "Select Top 100 * From [Person].[PersonPhone];";
MyCommand.CommandType = CommandType.Text;
MyCommand.Connection = MyConnection;
 
MyCommand.Connection.Open();
 
SqlDataAdapter sda = new SqlDataAdapter(MyCommand);
myData md = new myData();
sda.Fill(md, "PersonPhone");
 
md.PersonPhone[0].PhoneNumber = "000-000-0000";
 
GridView.DataSource = md;
GridView.DataBind();
            
MyCommand.Dispose();
MyConnection.Dispose();
Typed DataSet 을 사용하면 위 예제처럼 md.PersonPhone[0].PhoneNumber 과 같이 Table 명명을 구체화 할 수 있게 됩니다.

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] IAsyncResult 인터페이스  (0) 2015.04.20
[ASP.NET] LINQ 활용  (0) 2014.10.07
[ASP.NET] DataSet  (0) 2014.10.06
[ASP.NET] WaitHandle  (0) 2014.10.02
[ASP.NET] SqlCommand  (0) 2014.09.20
[ASP.NET] SqlParameter  (0) 2014.09.05
0 0
Programming/.NET

이 클래스는 일부 혹은 전체 비동기 프로세스가 끝날때 까지 대기하는등 여러 목적을 위한 추상클래스입니다. 하나 이상의 데이터베이스 비동기 명령을 처리하려는 경우 각 비동기 프로세스를 위한 대기 핸들을 포함하는 배열을 생성할 수 있으며 WaitHandle 클래스의 정적 메소드를 사용함으로서 전체나 혹은 일부 배열에서의 대기 핸들을 프로세스가 완료될때가지 실행할 수 있습니다.

다음은 WaitHandle 클래스가 가지고 있는 대략적인 메소드 목록입니다.

 WaitOne 이 메소드는 단독 비동기 프로세스가 완료되거나 타임아웃에 걸릴때까지 대기하는 메소드입니다. 프로세스가 성공적으로 완료되면 True 를 타임아웃에 걸리는등의 실패에는 False 값을 가지는 Boolean 형의 값을 반환합니다.
 WaitOne (milliseconds, exitContext) 이 메소드는 WaitOne 메소드의 오버라이드 메소드로서 첫번째 Paramter 로 Integer 형식의 값을 받습니다. 이 값은 millisecond 단위의 타임아웃값을 나타냅니다. 두번째 Paramter 로는 메소드가 비동기 컨텍스트를 요구하는지의 여부를 지정하는 Boolean 형의 값을 받으며 비동기 처리를 위해서는 값을 False 로 지정합니다.
 WaitOne (timeSpan, exitContext) TimeOut 값으로서 TimeSpan 객체를 받는 오버라이드 메소드입니다. 두번째 Parameter 는 위 메소드와 동일합니다.
 WaitAny (waitHandles) 이 메소드는 배열형태로서 하나 이상의 WaitHandle 관리하기 위해 사용되는 정적메소드입니다. 이미 시작된 비동기 프로세스나 처리가 시작된 배열안에 대기 핸들에 대한 대기수행에 사용되는 메소드입니다. 하나 이상의WaitHandle 을 위해서는 반드시 WaitAny 메소드가 반복적으로 호출되어야 합니다.
 WaitAny (waitHandles, milliseconds, exitContext) 위 메소드와 같으나 millisecond 형태의 TimeOut 값과 두번째 Paramter 로 메소드가 비동기 컨텍스트를 요구하는지의 여부를 지정하는 Boolean 형의 값을 받습니다. 참고로 비동기 처리를 위해서는 값을 False 로 지정합니다.
 WaitAny (waitHandles, timeSpan, exitContext) 위 메소드와 같으나 두번째 Parameter 에서 TimeOut 값으로서의 TimeSpan 객체를 받습니다.
 WaitAll (waitHandles) 모든 비동기 프로세스가 동작을 끝낼때 까지 사용되는 정적 메소드입니다.
 WaitAll (waitHandles, milliseconds, exitContext) 위 메소드와 같으나 millisecond 형태의 TimeOut 값과 메소드가 비동기 컨텍스트를 요구하는지의 여부를 지정하는 Boolean 형의 값을 받습니다.
 WaitAll (waitHandles, timeSpan, exitContext) 위 메소드와 같으나 두번째 Parameter 에서 TimeOut 값으로서의 TimeSpan 객체를 받으며 세번째 Paramter 에서 메소드가 비동기 컨텍스트를 요구하는지의 여부를 지정하는 Boolean 형의 값을 받습니다.
 Close () 모든 대기 핸들을 해제하여 이들 리소스를 회수하는 메소드입니다.

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] LINQ 활용  (0) 2014.10.07
[ASP.NET] DataSet  (0) 2014.10.06
[ASP.NET] WaitHandle  (0) 2014.10.02
[ASP.NET] SqlCommand  (0) 2014.09.20
[ASP.NET] SqlParameter  (0) 2014.09.05
[ASP.NET] ADO.NET 의 네임스페이스와 클래스  (0) 2014.09.01
0 0
Programming/.NET
ADO 등 ADO.NET 이전버전에서 Data 를 처리할때 방식은 다음 명령이 실행되기 위해 이전 명령이 처리완료될때까지 대기하는 순차적인 처리방식이었습니다. 그러나 ADO.NET 2.0 이래 사용자들은 데이터베이스 명령을 비동기적으로 처리할 수 있게 되었습니다. 이것은 애플리케이션이 처리완료까지 대기할 필요없이 다음 명령을 실행할 수 있다는 것을 의미하며 특히 서로 종속되지 않는 다중 데이터소스에 접근시 유용하게 대응할 수 있는 방안을 제시합니다.

 SqlCommand

SqlCommand 클래스에서 지원하는 비동기 메소드는 아래와 같습니다.

 Method  설명
 BeginExecuteNonQuery() 결과값을 반환하지 않는 쿼리를 비동기적으로 수행하는 메소드입니다. 메소드 처리 결과는 IAsyncResult 인터페이스를 구현하는 객체를 반환하며참조하며 해당 객체는 메소드가 동작하거나 처리가 완료되는 시점을 감지할 수 있는 용도로 사용될 수 있습니다.
 BeginExecuteNonQuery (callback, stateObject) 오버로드된 메소드로서 비동기 처리를 수행하며 AsynchCallback 인터페이스의 객체를 전달받습니다. 메소드에서 callback Parameter 는 메소드의 처리가 끝난 후 호출되는 것으로 완료대기없이 callback 으로 전달되는 메소드 처리를 진행할 수 있도록 합니다. 두번째 Parameter 인 사용자 정의 객체를 전달받는데 이 객체는 callback 메소드에 자동적으로 전달됩니다. callback 메소드는 IAsyncResult 인터페이스의 AsyncState 속성을 통해 사용자 장의 객체의 상태를 확인할 수 있습니다.
 EndExecuteNonQuery (asyncResult) BeginExecuteNonQuery 메소드로 부터 결과를 엑세스하는데 사용되며 BeginExecuteNonQuery 를 호출할때 반환된 lAsyncResult 객체전달을 전달합니다. 메소드실행의 결과값으로는 적용된 Row 수를 반환합니다.
 BeginExecuteReader 결과집합을 반환하는 쿼리를 비동기로 수행한다는 차이점만 제외하면 BeginExecuteNonQuery 메소드와 동일합니다.
 BeginExecuteReader (commandBehavior) BeginExecuteReader 메소드와 동일하나 commandBehavior Parameter 를 가집니다.
 BeginExecuteReader (callback, stateObject) BeginExecuteReader 메소드와 기본적인 동작이 같으며 Paramter 는 BeginExecuteNonQuery 의 경우와 같습니다.
 BeginExecuteReader (callback, stateObject, commandBehavior) 이 오버로드된 메소드는 AsyncCallback 클래스의 인스턴스를 가지며 이것을 통해 프로세스가 동작을 종료할때 callback 메소드를 호출하는데 사용합니다. 두번째 Parameter 는 callback 메소드에 전달하기 위한 사용자 객체이며 세번째 Paramter 는 동기 ExecuteReader 메소드와 같은 command behavior 열거형을 사용합니다.
 EndExecuteReader 이 메소드는 BeginExecuteReader 메소드로 부터 결과를 엑세스하는데 사용되며 BeginExecuteReader 메소드를 호출할때 수신된 lAsyncResult 인터페이스 객체를 전달해야 합니다. 메소드는 또한 실행결과로서 쿼리실행의 결과집합을 포함하는 SqlDataReader 객체를 반환합니다.
 BeginExecuteXmlReader BeginExecuteReader 와 같으나 XML 형태의 결과집합을 반환하는 쿼리를 수행한다는 차이가 있습니다.
 BeginExecuteXmlReader (callback, stateObject)  BeginExecuteReader (callback, stateObject) 메소드와 같습니다. 다만 XML 형식의 데이터를 받습니다.
 EndExecuteXmlReader  EndExecuteReader (callback, stateObject) 메소드와 같습니다. 다만 XML 형식의 데이터를 받습니다.

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] DataSet  (0) 2014.10.06
[ASP.NET] WaitHandle  (0) 2014.10.02
[ASP.NET] SqlCommand  (0) 2014.09.20
[ASP.NET] SqlParameter  (0) 2014.09.05
[ASP.NET] ADO.NET 의 네임스페이스와 클래스  (0) 2014.09.01
[ASP.NET] LinkButton  (0) 2014.08.27
0 0
Programming/.NET
데이터 베이스관련 프로그래밍 작업시 SQL 구문에서 Parameter 사용은 반드시 사용되어야 하는 필수사항은 아니지만 SQL injection 공격을 방어하는데 충분한 도움을 줄 수 있으므로 귀찮더라도 되도록 SqlParamter 사용을 권장합니다 . 실제작업시 SqlParamter 클래스의 인스턴스로서 생성되는 Parameter 는 이름, 값, 데이터형등의 필수정보 속성을 설정함으로서 사용됩니다.

 ParameterName  Parameter 이름을 설정하거나 설정된 값을 가져옵니다.
 SqlDbType  Paramter 값에 해당하는 SQL 데이터베이스의 데이터형을 설정하거나 설정된 값을 가져옵니다.
 Size  Paramter 값의 크기를 설정하거나 설정된 값을 가져옵니다.
 Direction  Input 혹은 Output 등의 Direction 을 설정하거나 설정된 값을 가져옵니다.
 Value  Paramter 에서 처리될 실제 값을 설정하거나 설정된 값을 가져옵니다.

아래는 SqlParamter 이용시 예제코드입니다.
SqlConnection MyConnection = new SqlConnection();
 
MyConnection.ConnectionString = ConfigurationManager.ConnectionStrings["new_connection"].ConnectionString;
            
SqlCommand MyCommand = new SqlCommand();
MyCommand.CommandText = "Select Top 100 * From [Person].[PersonPhone] Where PhoneNumber = @pn";
MyCommand.CommandType = CommandType.Text;
MyCommand.Connection = MyConnection;
 
SqlParameter sp = new SqlParameter();
sp.ParameterName = "@pn";
sp.SqlDbType = SqlDbType.NVarChar;
sp.Size = 25;
sp.Direction = ParameterDirection.Input;
sp.Value = "849-555-0139";
 
MyCommand.Parameters.Add(sp);
 
SqlDataAdapter MyAdapter = new SqlDataAdapter();
MyAdapter.SelectCommand = MyCommand;
            
DataTable MyTable = new DataTable();
MyAdapter.Fill(MyTable);
GridView.DataSource = MyTable.DefaultView;
GridView.DataBind();
 
MyCommand.Connection.Open();
 
MyAdapter.Dispose();
MyCommand.Dispose();
MyConnection.Dispose();
쿼리구문을 설정하는 MyCommand 객체의 CommandText 속성에서 우선 Paramter 로 사용할 조건절을 작성하고 해당 Paramter의 이름을 SqlParamter 클래스 객체의 ParamterName 속성으로 설정합니다. 그리고 다른 설정사항인 SqlDbType 이나 Size 등의 정보도 같이 지정하도록 합니다.

Paramter 의 모든 속성 설정이 완료되면 SqlCommand 객체의 Parameters.Add 메소드로 위에서 설정한 Paramter 인스턴스를 전달해 Paramter 를 추가하면 Paramter 에 관한 모든 작업이 완료됩니다. 만약 2개 이상의 Paramter 설정이 필요하다면 필요한 만큼의 SqlParamter 클래스 객체를 선언해야 합니다.

만약 같은 SQL 쿼리에서 Paramter 를 사용하지 않는다고 한다면
MyCommand.CommandText = "Select Top 100 * From [Person].[PersonPhone] Where PhoneNumber = '849-555-0139'";
처럼 값을 바로 지정하거나 변수를 대입해 사용할 수 있습니다.

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] WaitHandle  (0) 2014.10.02
[ASP.NET] SqlCommand  (0) 2014.09.20
[ASP.NET] SqlParameter  (0) 2014.09.05
[ASP.NET] ADO.NET 의 네임스페이스와 클래스  (0) 2014.09.01
[ASP.NET] LinkButton  (0) 2014.08.27
[ASP.NET] DataReader  (0) 2014.08.22
0 0
Programming/.NET
.NET Framework 은 ADO.NET 과 관련한 6개의 핵심 네임스페이스를 가지고 있습니다. 더불어 몇몇 데이터 공급자는 자기 자신만의 네임스페이스를 가질 수 있는데 예를 들어 SQL Server 를 대상으로하는 .NET 데이터 공급자를 System.Data.SqlClient 에 추가하는 등의 구현이 가능합니다.

 System.Data ADO.NET 의 가장 핵심이자 상위에 속하는 네임스페이스이며 데이터공급자에 의해 사용되는 클래스와 테이블, 행, 열및 데이터셋(DataSet)등을 표현하기 위한 클래스를 포함하고 있습니다. 또한 여기에는 .NET 의 관리공급자에 의해 사용되며 ADO.NET 와 연결하기 위한 IDbCommand, IDbConnection, IDbDataAdapter 등의 인터페이스를 포함합니다.
 System.Data.Common 데이터 공급자의 기반클래스로 사용되는 공용클래스를 정의합니다. 모든 데이터 공급자는 이들 클래스를 공유하여 사용합니다.
 System.Data.OleDb  .NET OLEDB 와 관련된 데이터 처리 구현시 사용되는 클래스(OleDbConnection, OleDbCommand 포함)를 정의합니다.
 System.Data.Odbc  .NET ODBC 와 관련된 데이터 처리 구현시 사용되는 클래스(OdbcConnection, OdbcCommand 포함)를 정의합니다.
 System.Data.SqlClient  MS SQL Server 7.0 혹은 그 상위 버전을 위한 데이터 공급자를 정의합니다. 이것은 SqlConnection 과 SqlCommand 클래스를 포함하고 있습니다.
 System.Data.SqlTypes  이 네임스페이스는 SQL Server DB 의 특정 데이터타입을 표현하기 위한 클래스를 정의합니다.

ADO.NET 은 비연결, 공유, 데이터공급자인 세가지의 독특한 형식의 클래스를 가지고 있는데 우선 비연결 클래스는 ADO.NET Framework 의 기본구조를 제공하는 클래스이며 대표적인 사례로 DataTable 클래스등을 들 수 있습니다. 이 클래스의 객체는 특정 데이터 공급자에 의존하지 않고 데이터를 자체적으로 저장할 수 있습니다.

데이터 공급자의 기본 클래스인 공유클래스는 모든 데이터공급자에서 공유되는 클래스이며 마지막으로 데이터 공급자 클래스는 서로 다른 종류의 데이터 소스를 사용하는 작업을 위한 클래스입니다. 이는 특정 데이터베이스의 데이터관리를 수행하는데 사용됨을 의미하는 것으로 예를 들어 SqlClient 데이터 공급자인 경우는 (MS) SQL Server 를 대상으로 하는 데이터 공급자에 해당합니다.

또한 데이터 공급자는 Connection, Command, DataAdapter, DataReader 객체등을 포함하고 있는데 이들 객체중 Connection은 ADO.NET 작업에 있어서 가정 먼저 생성하여 DB연결을 위한 연결문자열등의 정보를 제공하는 역활을 합니다.

Command 객체는 SQL 명령에 대한 객체인데 이때 SQL 문은 일반쿼리나 저장프로시저 등의 명령일 수 있으며 필요한 경우 파라메터정보를 포함할 수 있습니다. Command 객체를 통해 SQL 문을 수행하는 경우 별다른 결과값을 받지 않는다면 단순히 쿼리를 실행하는 것으로 끝내면 되지만 그렇지 않고 결과집합(쿼리 수행 후 돌려받는 Table 형식의 결과값)등의 데이터를 받는 경우 두가지 선택적 처리방식을 결정할 수 있습니다.

첫번째로 결과집합을 데이터베이스의 연결을 유지하지 않고 계속 사용하고자 한다면 결과집합을 가지는 객체인 DataAdapter 로 부터 DataSet 이나 DataTable 객체에 결과집합을 저장해야 합니다. DataSet / DataTable 객체는 비연결상태에서도 관련 정보를 계속 유지할 수 있도록 합니다.

반면 결과집합을 한번만 처리하고 계속 유지할 필요가 없다면 단순히 DataReader 객체에서 사용자에게 데이터를 표시하고 끝낼 수 있습니다. 이것은 이전의 방법보다 좀더 빠르고 간단한 방식에 해당하지만 DataReader 객체는 데이터 소스 서버와의 연결을 계속 유지해야 하며 오직 앞으로만 순환이 가능합니다. DataRader 에 저장된 결과값을 순환해 읽기시작하면 다시 이전데이터를 읽어올 수 없으며 이 경우에는 데이터소스 서버로부터 다시 쿼리를 날려 결과집합을 가져와야 합니다. 또한 DataReader 의 결과집합은 변경할 수 없는 읽기전용 커서로서 어떤 형식으로든 변경이 필요하다면 이전에 언급한 DataSet 이나 DataTable 객체를 사용해야 합니다.

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] SqlCommand  (0) 2014.09.20
[ASP.NET] SqlParameter  (0) 2014.09.05
[ASP.NET] ADO.NET 의 네임스페이스와 클래스  (0) 2014.09.01
[ASP.NET] LinkButton  (0) 2014.08.27
[ASP.NET] DataReader  (0) 2014.08.22
[ASP.NET] 인라인 데이터 바인딩 구문  (0) 2014.08.21
0 0
Programming/.NET
LinkButton 은 대부분의 사용방법이 Button과 동일하며 작동 방식도 같습니다.

 주요 속성/이벤트
<asp:LinkButton ID="LinkButton1" runat="server">링크버튼</asp:LinkButton>

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] SqlParameter  (0) 2014.09.05
[ASP.NET] ADO.NET 의 네임스페이스와 클래스  (0) 2014.09.01
[ASP.NET] LinkButton  (0) 2014.08.27
[ASP.NET] DataReader  (0) 2014.08.22
[ASP.NET] 인라인 데이터 바인딩 구문  (0) 2014.08.21
[ASP.NET] LinqDataSource - 생성및 바인딩  (1) 2014.07.01
0 0
Programming/.NET
DataReader 는 정방향 읽기전용 커서로서 데이터 소스로의 실제연결이 이루어진 상태에서 결과집합의 전체나 혹은 특정부분을 순환하는데 가장 성능이 좋은 것으로 알려져 있습니다.

다만 DataReader 객체는 데이터 순환이 완료되는 시점에서 Close 메소드를 통한 데이터 소스로의 연결해제가 필요하며 그렇지 않으면 서버의 연결자원을 낭비하는 결과를 가져오게 됩니다.

연결을 닫는 첫번째 절차는 Command 객체의 Execute 메소드를 호출할때 특정 특정 파라메터를 붙여 주는 방법입니다. 파라메터 값은 CommandBehavior.CloseConnection 열거값이며 이것은 DataReader 를 통해 데이터를 순환하다가 끝에 도달하는 경우 자동적으로 연결을 Close 하도록 처리할 수 있습니다. 다만 끝에 도달하기도 전에 데이터 순환을 중단하는 경우라면 수동으로 직접 Connection 객체의 Close() 메소드를 호출해야 하며 수동적으로 연결을 끊는 이런 처리가 두번째 방법에 해당됩니다.

SqlConnection MyConnection = new SqlConnection();
 
MyConnection.ConnectionString = ConfigurationManager.ConnectionStrings["new_connection"].ConnectionString;
            
SqlCommand MyCommand = new SqlCommand();
MyCommand.CommandText = "Select Top 100 * From [Person].[PersonPhone];";
MyCommand.CommandType = CommandType.Text;
MyCommand.Connection = MyConnection;
MyCommand.Connection.Open();
 
SqlDataReader MyReader = MyCommand.ExecuteReader(CommandBehavior.CloseConnection);
 
while (MyReader.Read())
    Response.Write("Phone : " + MyReader.GetString(1) + "<br />");
            
MyCommand.Dispose();
MyConnection.Dispose();
참고로 SqlCommand 의 ExecuteReader 메소드는 연결과 CommandText 에 지정한 쿼리를 실행시키는 메소드에 해당합니다.

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] ADO.NET 의 네임스페이스와 클래스  (0) 2014.09.01
[ASP.NET] LinkButton  (0) 2014.08.27
[ASP.NET] DataReader  (0) 2014.08.22
[ASP.NET] 인라인 데이터 바인딩 구문  (0) 2014.08.21
[ASP.NET] LinqDataSource - 생성및 바인딩  (1) 2014.07.01
[ASP.NET] ADO.NET 기본  (3) 2014.06.26
0 0
Programming/.NET
ASP.NET 은 인라인에서 데이터를 바인딩 하기 위한 특정한 구문을 제공합니다. GridView 와 같은 컨트롤에서는 데이터소스만 지정해 주면 알아서 바인딩을 처리하지만 그렇지 못할 상황에서는 개발자가 임의로 어떤 데이터를 바인딩하면 좋을지 지정해 줄 필요가 있습니다.

예를 들어 Repeater 와 같은 컨트롤을 사용한다고 했을때 Repeater 는 자체적으로 아무것도 표시하지 않은 템플릿 컨트롤로서 내부 컨텐츠를 직접 정의해야 합니다. 만약 Repeater 에 SqlDataSource 를 지정했다면 내부적으로 어떤 데이터를 바인딩 해야 하는지 다음과 같은 방법으로 구현해야 하는 것입니다.
<asp:Repeater ID="Repeater1" runat="server" DataSourceID="SqlDataSource1">
    <HeaderTemplate>
        <table>
    </HeaderTemplate>
        <ItemTemplate>
        <tr>
            <td>
                <%# Eval("BusinessEntityID") %>
            </td>
            <td>
                <%# Eval("PhoneNumber") %>
            </td>
            <td>
                <%# Eval("ModifiedDate") %>
            </td>
        </tr>
        </ItemTemplate>
    <FooterTemplate>
        </table>
    </FooterTemplate>
</asp:Repeater>
위 예제에서 사용된 Eval 메소드는 데이터소스로 부터 가져올 특정 Item 을 지정하여 해당 영역에 표시할 수 있도록 하는 메소드이며 인라인 데이터 바인딩에서 가장 기본적으로 사용되는 구문입니다.

Eval 메소드를 사용할 때 해당 Item 에 대해서 특정 포멧을 적용해야 하는 경우 직접 원하는 포멧을 지정할 수 있도록 메소드를 오버라이드 할 수 있습니다.
<td>
    <%# Eval("ModifiedDate", "{0:yyyy-MM-dd}") %>
</td>
필요하다면 연산자를 사용해 다른 문자열과 같은 요소와 결합할 수도 있으며
<td>
    <%# "ID 값 : " + Eval("BusinessEntityID") %>
</td>
특정 메소드에 Item 값을 넘겨 원하는 처리를 진행할 수도 있습니다.
<td>
    <%# phone_to_name(Eval("PhoneNumber")) %>
</td>
참고로 Eval 이외에 데이터 바인딩 구문으로 Bind 메소드가 사용되기도 합니다. 흔히 2-way 바인딩이라고 하는 이 메소드는 Eval 처럼 Item 값을 읽기위한 역활 뿐 아니라 데이터를 수정하기 위한 동작에도 사용되는 메소드입니다.

따라서 GridView 나 DetailsView 등 데이터 편집이 가능한 컨트롤에 사용되어야 합니다.
<td>
    <asp:TextBox ID="TextBox1" runat="server" Text='<%# Bind("PhoneNumber") %>'></asp:TextBox>
</td>
0 0
Programming/.NET
SQL 데이터베이스에 직접적으로 연결하여 쿼리를 처리하는 SqlDataSource 컨트롤과는 달리 LinqDataSource 는 대상이 되는 DB 데이터를 객체화 하여 LINQ 를 통해 처리할 수 있도록 하는 컨트롤입니다.

LinqDataSource 컨트롤을 사용하기 전에 우선 LINQ to SQL 을 통해 다루고자 하는 데이터의 Data Context 클래스를 생성하여야 합니다.

프로젝트에서 마우스 오른쪽 버튼을 눌러 Add -> New Item 을 선택합니다.


Add New Item 화면에서 왼쪽 Data 카테고리를 선택하고 오른쪽 LINQ to SQL Classes 항목을 선택한 뒤 Add 버튼을 눌러줍니다. 이때 이름(Name)은 원하는대로 지정해도 됩니다.

위 단계를 거치고 나면 프로젝트에 .dbml 파일이 생성되고 해당 디자이너 화면이 보여질 것입니다. 이제 데이터 서버에 연결하여 대상이 될 테이블을 가져오도록 하겠습니다.

Visual Studio 의 Server Explorer 에서 Data Connections 을 우클릭 한 다음 Add Connection 메뉴를 선택합니다.


Server Name 에 대상 서버이름이나 IP 등을 입력하고 Log on to the server 에 접속가능한 계정을 설정합니다. 그러면 Select or enter a database name 에 사용가능한 DB 목록이 보여질 것입니다. 해당 목록에서 다루고자 하는 대상이 있는 DB를 선택하고 OK 버튼을 눌러줍니다.


Server Explorer 화면에 방금전 등록한 DB 가 연결되었음을 확인할 수 있습니다. 해당 DB 에서 원하는 테이블을 dbml 디자이너 화면에 끌어다 놓습니다.

dbml 파일을 저장하고 LinqDataSource 를 사용하고자 하는 aspx 페이지의 디자이너화면에서 Visual Studio Toolbox 의 Data 카테고리 안에 있는 LinqDataSource 컨트롤을 마우스로 끌어다 놓습니다.


LinqDataSource 컨트롤의 SmartTag 를 클릭하여 'Configure Data Source' 항목을 선택합니다.


이 화면에서 Choose your context object 에 있는 항목중 데이터소스로 활용하고자 하는(이전 단계에서 생성한) 데이터 컨텍스트 객체를 선택할 수 있으며 여기에는 System.data.Linq.DataContext 클래스 에서 파생된 객체항목이 나열됩니다. 참고로 System.data.Linq.DataContext 클래스는 LINQ to SQL 에 의해 생성된 데이터 컨텍스트 클래스에 해당됩니다.

▶ <그림 1-1>

위 화면은 Choose a Context Object 화면에서 원하는 컨텍스트 객체를 선택하고 'Next' 버튼을 누른 뒤 화면으로 여기에서는 이전에 선택한 객체의 데이터 항목중 실제 바인딩하고자 하는 항목을 선택할 수는 화면입니다. 실제 위 화면에 나오는 항목은 샘플데이터베이스(AdventureWorks2012)의 Person.Person 테이블의 열항목인데 만약 대상 클래스가 DataContext 에서 파생된 클래스가 아닌 다른 클래스의 형태라면 해당 클래스에 있는 배열등의 속성항목등을 볼 수 있게 됩니다.

<그림 1-1>에서 특정 필드를 선택하면 <코드 1-1>과 같이 선택한 필드를 포함한 LINQ 쿼리가 생성될 것입니다.
<asp:LinqDataSource ID="LinqDataSource1" runat="server" ContextTypeName="Webtest.DataClasses1DataContext" EntityTypeName="" Select="new (Title, FirstName, MiddleName)" TableName="Persons"></asp:LinqDataSource>
▶<코드 1-1>

실제 <코드 1-1>의 LinqDataSource 를 GridView에 바인딩해 보면 다음과 같은 결과를 볼 수 있습니다.
<asp:GridView ID="GridView1" runat="server" DataSourceID="LinqDataSource1"></asp:GridView>
1 0
Programming/.NET
ADO.NET 은 .NET Framework 1.0 부터 포함된 핵심 컴포넌트에 해당하며 오늘날 데이터에 접근할 수 있는 다양한 방법을 제시함으로써 근본적으로 데이터를 다루기 위한 여러 기능을 제공하고 있습니다.

ADO.NET 이전의 ADO 는 데이터베이스로부터 지속적으로 데이터 연결을 유지한 상태에서 필요한 데이터를 다루어야 했는데 연결상태가 계속해서 유지되어야 한다는 면은 비효휼적인 면을 드러냈고 곧 비연결상태에서도 데이터를 다룰 수 있어야 한다는 요구가 제시되었습니다.

비연결의 근본적인 동작방식은 데이터를 특정 컬렉션에 채워넣고 DB와의 연결을 끊은상태에서 컬렉션에 채워진 데이터를 다루는 것입니다. ADO.NET 의 DataSet 이 바로 그러한 역활을 수행하는데 컬렉션에 채워진 데이터는 데이터베이스와는 분리된 상태이지만 데이터내용은 물론 모든 테이블정보(열, 행, 릴레이션관한 것등)를 완벽히 유지하면서 데이터를 다룰 수 있습니다.

사실 이게 중요한데 이전 ADO 에서는 데이터를 담아두기 위한 단독적인 테이블이 필요했으며 이것은 데이터베이스의 테이블정보를 전혀 반영하지 않은 것이었습니다.

또한 ADO.NET 은 통합된 프로그래밍 모델로서 서버나 클라이언트 모두 같은 방법으로 데이터를 다룰 수 있어서 기존 ADO 보다는 좀더 나은 생산성을 기대할 수 있습니다.

 Select

데이터 소스를 연결하고 나서 단순히 데이터를 읽어오기만 하는 경우라면 간단히 DataReader 클래스를 사용할 수 있습니다.
public List<string> GetPersonPhone()
{
    string strCmd = "Select * From [Person].[PersonPhone];";
 
    SqlConnection conn = new SqlConnection(@"Data Source=localhost;Initial Catalog=AdventureWorks2012;User ID=sa;Password=123");
    SqlCommand cmd = new SqlCommand(strCmd, conn);
    conn.Open();
 
    List<string> rtn = new List<string>();                
            
    SqlDataReader SqlReader = cmd.ExecuteReader(CommandBehavior.CloseConnection);                
 
    while (SqlReader.Read())
        rtn.Add(SqlReader["PhoneNumber"].ToString());
 
    return rtn;
}
▶<코드 1-1>

<코드 1-1>은 AdventureWorks2012 DB의 Person.PersonPhone 테이블의 내용을 가져와 그 중 PhoneNumbe
r 컬럼의 데이터를 List 에 담고 반환하는 예제입니다.

DB 서버의 연결을 위해 SqlConnection 클래스의 인스턴스를 생성해 연결문자열을 지정하고 뒤이어 SqlCom
mand 객체를 생성하면서 데이터를 가져오기 위한 쿼리문과 SqlConnection 객체를 전달합니다. 여기까지 하고 나면 DB연결준비는 끝난것으로 SqlConnection 객체의 Open 함수를 호출하여 지정한 DB를 열도록 합니다.

SqlCommand 클래스가 쿼리문을 실행하는 클래스로서 ExecuteReader 메소드를 호출해 쿼리를 전달하고 반환된 SqlDataReader 객체의 Read() 메소드를 순환호출함으로서 실제 내용을 읽어오도록 합니다. 그리고 모든 데이터를 배열이나 리스트등에 담게 되면 DB와의 연결은 자동으로 닫히게 됩니다.

 Insert

Insert 는 Select 처리가 별반 다르지 않습니다. 쿼리문을 Insert 에 맞게 수정하고 Select 때의 ExecuteReader 메소드 대신에 ExecuteNonQuery 메소드를 호출하는 것이 전부입니다.
public void AddPersonPhone()
{
    string strCmd = "Insert Into [Person].[PersonPhone] Values (20777, '1 (11) 500 555-1212', 1, GETDATE());";
 
    SqlConnection conn = new SqlConnection(@"Data Source=localhost;Initial Catalog=AdventureWorks2012;User ID=sa;Password=123");
    SqlCommand cmd = new SqlCommand(strCmd, conn);
    conn.Open();
 
    cmd.ExecuteNonQuery();
    conn.Close();
}
▶<코드 2-1>

<코드 2-1> 에서는 Select 때와는 달리 데이터를 담을 수 있는 배열등이 필요없으며 단지 DB 를 Open 한 이후 쿼리를 실행하는 ExecuteNonQuery 메소드를 바로 호출합니다. 다만 필요한 작업을 수행한 이 후 Close 메소드를 호출하여 DB 연결을 닫아주도록 합니다.

 Update

Table 의 Update 는 <코드 2-1> Insert 작업에서 쿼리만 Update 구문으로 바꿔주면 됩니다. 쉽죠?
public void ModifyPersonPhone()
{
    string strCmd = "Update [Person].[PersonPhone] Set PhoneNumber = '000-000-0000' Where BusinessEntityID = 20777;";
 
    SqlConnection conn = new SqlConnection(@"Data Source=localhost;Initial Catalog=AdventureWorks2012;User ID=sa;Password=123");
    SqlCommand cmd = new SqlCommand(strCmd, conn);
    conn.Open();
 
    cmd.ExecuteNonQuery();
    conn.Close();
}
▶<코드 3-1>

참고로 ExecuteNonQuery 함수는 쿼리 실행에 적용된 Table 의 Row 수를 반환합니다. 따라서 만일 Update 로 인해 변경된 Row 수를 알아야 한다면 ExecuteNonQuery 함수호출시 다음과 같은 방법으로 결과값을 가져오면 됩니다.
int updateRow = cmd.ExecuteNonQuery();
이러한 처리 방법은 Insert 나 Delete 등에도 똑같이 적용될 수 있습니다.

 Delete

Delete 는 Insert 나 Update 와 비교해 쿼리문만 다를 뿐 모든처리과정이 같습니다.

public void delPersonPhone()
{
    string strCmd = "Delete From Person.PersonPhone Where BusinessEntityID = 20777;";
 
    SqlConnection conn = new SqlConnection(@"Data Source=localhost;Initial Catalog=AdventureWorks2012;User ID=sa;Password=123");
    SqlCommand cmd = new SqlCommand(strCmd, conn);
    conn.Open();
 
    int updateRow = cmd.ExecuteNonQuery();
    conn.Close();
}
3 0
Programming/.NET
LinqDataSource 컨트롤 생성시 설정마법사를 통해서도 어느정도의 데이터 필터링을 위한 기능을 제공하지만  QueryExtender 를 사용하면 좀더 다양한 방법으로 데이터 필터링을 수행할 수 있습니다.

QueryExtender 는 다중검색이나 데이터 검색범위, 콤마(,)를 통한 OrderBy 다중필드 처리를 수행할 수 있을 뿐만 아니라 사용자 정의 표현식의 적용도 가능합니다. 아래 표는 현재 사용할 수 있는 필터링 표현식 항목입니다.

 SearchExpression  문자열이나 검색이나 비교를 수행합니다.  특히 SearchType 속성을 사용하면 StartsWith, EndsWith, Contains 를 이용한 검색도 가능합니다. 
 RangeExpression  최소값과 최대값을 지정해 해당 범위의 값을 찾도록 합니다.
 OrderByExpression  데이터를 순차적으로 정렬합니다.
 CustomExpression  사용자 LINQ 표현식을 사용하여 필터링을 수행할 수 있도록 합니다.
 MethodExpression  사용자 LINQ 쿼리를 포함하는 메소드를 지정할 수 있도록 합니다.
 PropertyExpression  특정 컬럼의 속성을 필터링대상으로 처리합니다.
 OfTypeExpression  데이터 타입을 필터링대상으로

QueryExtender 는 IQueryableDataSource 인터페이스를 구현해 LinqDataSource 나 EntityDataSource 컨트롤등 데이터 소스 컨트롤하위에서 작동할 수 있습니다.
<asp:LinqDataSource ID="LinqDataSource1" runat="server" ContextTypeName="Webtest.DataClasses1DataContext" EntityTypeName="" Select="new (key as LastName, it as Persons, Sum(EmailPromotion) as Sum_EmailPromotion)" TableName="Persons" GroupBy="LastName" Where="BusinessEntityID <= 100"></asp:LinqDataSource>
<asp:QueryExtender ID="QueryExtender1" runat="server" TargetControlID="LinqDataSource1">
    <asp:SearchExpression DataFields="LastName">
        <asp:QueryStringParameter DefaultValue="Baker" />
    </asp:SearchExpression>
</asp:QueryExtender>
QueryExtender 사용시 필터링을 적용하기 위한 데이터소스컨트롤은 TargetControlID 로 지정하며 하위에 원하는 Expression Type을 추가하여 필터링을 적용합니다.
1 0
Programming/.NET
GridView는 Table의 전체 Row를 Grid에 뿌리지만 DetailsView 컨트롤은 한번에 하나의 레코드에 해당하는 데이터만을 볼 수 있게 합니다. Table의 Row를 하나씩 표시하면서 데이터의 추가, 삭제, 변경또한 가능한 컨트롤입니다.

DetailsView 컨트롤의 사용은 어렵지 않으며 다른 데이터 컨트롤과 마찬가지로 데이터소스를 지정해 주기만 하면 기본적인 기능을 바로 수행할 수 있습니다.
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:new_connection %>" SelectCommand="SELECT * FROM [Person].[PersonPhone]"></asp:SqlDataSource>
<asp:DetailsView ID="DetailsView1" runat="server" Height="50px" Width="425px" DataSourceID="SqlDataSource1"></asp:DetailsView>
보시는 바와같이 DetailsView 컨트롤은 데이터소스컨트롤에서 반환하는 데이터중 하나의 레코드에 해당하는 데이터만을 출력합니다.

▶ <그림 1-1>

DetailsView 는 데이터 소스의 쿼리결과 반환되는 데이터항목중 가장 처음것만을 표시하게 되는데 모든 데이터 항목을 하나씩 순환해 보려면 AllowPaging 속성을 true로 설정하여 페이징기능을 부여하면 됩니다.
<asp:DetailsView ID="DetailsView1" runat="server" Height="50px" Width="425px" DataSourceID="SqlDataSource1" AllowPaging="true"></asp:DetailsView>
또한 GridView 처럼 PagerSettings- 속성을 통해 페이징이 구현되는 부분에 대한 스타일을 재정의 하는것도 가능합니다.

 표시항목 수정

GridView와 마찬가지로 해당 Row의 열전체를 표시하는 DetailsView 컨트롤은 동작방식을 수정하여 특정 열(Column)에 대한 데이터만 따로 표시할 수 있도록 지정할 수 있습니다.
<asp:DetailsView ID="DetailsView1" runat="server" Height="50px" Width="425px" DataSourceID="SqlDataSource1" AllowPaging="true" AutoGenerateRows="false">
    <Fields>
        <asp:BoundField ReadOnly="True" HeaderText="BusinessEntityID" DataField="BusinessEntityID" Visible="false" />
        <asp:BoundField HeaderText="PhoneNumber" DataField="PhoneNumber" />
        <asp:BoundField HeaderText="PhoneNumberTypeID" DataField="PhoneNumberTypeID" />
        <asp:BoundField HeaderText="ModifiedDate" DataField="ModifiedDate" />
    </Fields>
</asp:DetailsView>
먼저 AutoGenerateRows 속성을 false 로 지정하여 자동적으로 데이터표시항목이 생성되는걸 막고 Fields 하위의 BoundField 객체를 사용해 표시할 열값을 일일이 지정해 주면 됩니다.

 GridView 와 연동하기

사실 DetailsView 컨트롤은 단독적으로 쓰이는 경우가 거의 없고 다른 데이터 컨트롤과 연동되어 특정 데이터에 대한 상세조회용도로 자주 사용됩니다. 여기서 말하는 연동가능한 컨트롤중에는 GridView 가 가장 대표적인 컨트롤이라 할 수 있겠습니다.

이런 경우를 생각해 보겠습니다. GridView에 표시된 데이터 항목에서 원하는 Row를 선택하는 경우 해당 Row에 대한 상세정보가 다시 DetailsView에 출력되는 경우입니다. 이런 시나리오를 구현하기 위해서는 다음과 같이 GirdView 컨트롤과 GridView 컨트롤 전용의 데이터소스 컨트롤을 배치해야 합니다.
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:new_connection %>" SelectCommand="SELECT * FROM [Person].[Person]"></asp:SqlDataSource>
<asp:GridView ID="GridView1" runat="server" DataSourceId="SqlDataSource1" AutoGenerateSelectButton="True" AllowPaging="True" DataKeyNames="BusinessEntityID"><SelectedRowStyle BackColor="AliceBlue" /></asp:GridView>
SqlDataSource 컨트롤의 Select 를 수정하여 Person.Person 테이블의 데이터를 가져오도록 하고 GridView에서 테이블로 표시합니다. 이때 GridView와 DetailsView 컨트롤 사이에 데이터를 가져오는 연결고리키로 DataKeyNames 속성을 지정합니다. 또한 GridView 컨트롤에서 선택항목을 구분하기 위해 SelectedRowStyle 을 사용하였습니다.
<asp:SqlDataSource ID="SqlDataSource2" runat="server" ConnectionString="<%$ ConnectionStrings:new_connection %>" SelectCommand="SELECT * FROM [Person].[PersonPhone]" FilterExpression="BusinessEntityID = '{0}'">
    <FilterParameters>
        <asp:ControlParameter Name="BusinessEntityID" ControlId="GridView1" PropertyName="SelectedValue" />
    </FilterParameters>
</asp:SqlDataSource>
<asp:DetailsView ID="DetailsView1" runat="server" DataSourceId="SqlDataSource2" AutoGenerateRows="True"></asp:DetailsView>
보시는 바와 같이 SqlDataSource 컨트롤은 GridView와 DetailsView 용도로 따로 생성합니다. SqlDataSource2 컨트롤에서는 FilterExpression 속성을 사용하여 [Person].[PersonPhone] 테이블에서 BusinessEntityID 에 주어지는 값에 해당하는 데이터만 가져오도록 하였습니다. 여기서 파라메터값은 ControlParameter 객체를 통해 GridView1 컨트롤에서 선택한 값중 BusinessEntityID 값이 주어지도록 지정되었습니다.


참고로 파라메터 지정에서 기존에 사용한 SelectParameters 는 SQL 쿼리단에서 Where 절로 추가가 가능하도록 하여 애초부터 파라메터에 해당하는 데이터만 가져오도록 제한된 데이터를 가져오게 됩니다. 데이터 자체가 제한된 데이터다 보니 다른 조건의 데이터가 필요한 경우 다시 데이터소스 컨트롤을 통해 데이터서버로 부터 새로운 데이터를 가져와야 하는 단점이 존재합니다.

반면 FilterParameters 를 사용하면 우선 데이터소스에서 모든 데이터를 가져와 서버의 메모리에 적재한 뒤 그 안에서 필터링을 적용하여 해당하는 데이터만을 표시하도록 합니다. 처음부터 모든 데이터를 가져와야 한다는 부담때문에 초기실행지연과 메모리소모에 대한 단점이 존재하지만 위 상황과 같이 선택항목마다 다른 내용을 빈번하게 보여줘야 하는 경우 메모리상에 존재하는 데이터만을 대상으로 필터링하게 되므로 데이터소스로 부터 서버에 원하는 데이터를 다시 조회해야 하는 경우가 불필요 하게 됩니다.

SelectParameters 나 FilterParameters 는 서로 장단점이 존재하므로 개발하고자 하는 환경에 맞게 적절히 골라 사용하시면 됩니다.

 데이터 추가/수정/삭제

DetailsView 를 이용하여 데이터를 추가/삭제/변경 하기 위해서는 DetailsView 컨트롤에 관련 기능을 하는 버튼(링크)을 생성하고 해당 DetailsView 의 데이터 소스 컨트롤에 실제 데이터처리를 위한 쿼리구문을 설정하기만 하면 됩니다.

예를 들어 데이터 추가에 대한 기능을 부여하고자 한다면 우선 DetailsView 에 AutoGenerateInsertButton 속성을 추가한뒤
<asp:DetailsView ID="DetailsView1" runat="server" DataSourceId="SqlDataSource2" AutoGenerateRows="True" AutoGenerateInsertButton="true"></asp:DetailsView>
데이터 소스 컨트롤에 InsertCommand 속성으로 데이터를 Insert 하는 쿼리구문을 지정합니다.
<asp:SqlDataSource ID="SqlDataSource2" runat="server" ConnectionString="<%$ ConnectionStrings:new_connection %>" SelectCommand="SELECT * FROM [Person].[PersonPhone]" FilterExpression="BusinessEntityID = '{0}'" InsertCommand="INSERT INTO [Person].[PersonPhone] VALUES(@BusinessEntityID, @PhoneNumber, @PhoneNumberTypeID, @ModifiedDate)">
    <FilterParameters>
        <asp:ControlParameter Name="BusinessEntityID" ControlId="GridView1" PropertyName="SelectedValue" />
    </FilterParameters>
</asp:SqlDataSource>
그러면 DetailsView 컨트롤 에는 'New' 라는 새로운 필드가 생기고


이 필드의 링크를 클릭하면 DB에 레코드를 추가할 수 있게 됩니다.


데이터를 삭제하거나 수정하는 경우도 위와 같은 순서로 설정하면 됩니다. 아래 <코드4-1>은 Insert, Update, Delete 의 모든 기능이 설정된 상태를 나타내고 있습니다.
<asp:SqlDataSource ID="SqlDataSource2" runat="server" ConnectionString="<%$ ConnectionStrings:new_connection %>" SelectCommand="SELECT * FROM [Person].[PersonPhone]" FilterExpression="BusinessEntityID = '{0}'" InsertCommand="INSERT INTO [Person].[PersonPhone] VALUES(@BusinessEntityID, @PhoneNumber, @PhoneNumberTypeID, @ModifiedDate)" DeleteCommand="DELETE FROM [Person].[PersonPhone] WHERE ([BusinessEntityID] = @BusinessEntityID)" UpdateCommand="UPDATE [Person].[PersonPhone] SET [PhoneNumber] = @PhoneNumber, [PhoneNumberTypeID] = @PhoneNumberTypeID, [ModifiedDate] = @ModifiedDate WHERE [BusinessEntityID] = @BusinessEntityID">
    <FilterParameters>
        <asp:ControlParameter Name="BusinessEntityID" ControlId="GridView1" PropertyName="SelectedValue" />
    </FilterParameters>
</asp:SqlDataSource>
<asp:DetailsView ID="DetailsView1" runat="server" DataSourceId="SqlDataSource2" AutoGenerateRows="True" DataKeyNames="BusinessEntityID" AutoGenerateInsertButton="true" AutoGenerateDeleteButton="true" AutoGenerateEditButton="true"></asp:DetailsView>
▶ <코드 4-1>
1 0
Programming/.NET
GridView 컨트롤은 데이터 집합을 사용자에게 보여주기 위해 ASP.NET 에서 사용할 수 있는 대표적 컨트롤입니다. GridView는 단순히 데이터를 화면에 표시하는 기능이외에도 데이터를 정렬하거나 게시판에서와 같은 페이징기능도 제공하며 심지어는 표시된 데이터를 임의로 수정할 수도 있습니다.

<코드 1-1>은 AdventureWorks2012 데이터베이스의 Person.Person 테이블에서 데이터를 Select 하는 SqlDataSource 컨트롤을 소스로 하여 GridView 컨트롤을 사용한 예제입니다.
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:new_connection %>" SelectCommand="SELECT * FROM [Person].[Person] WHERE ([PersonType] = @PersonType)">
    <SelectParameters>
        <asp:Parameter DefaultValue="EM" Name="PersonType" Type="String" />
    </SelectParameters>
</asp:SqlDataSource>

<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1"></asp:GridView>
▶ <코드 1-1>

데이터 소스를 GridView에 설정하고 페이지를 실행하면 데이터 소스의 스키마와 일치하는 컬럼을 자동으로 생성하여 화면에 표시하게 됩니다.

▶ <그림 1-1>

필요하다면 전체 컬럼을 그대로 가져오는 것이 아니라 데이터 소스의 쿼리를 수정하거나 아니면 GridView에 직접 특정 컬럼을 지정해 놓고 해당 컬럼만 생성하여 표시하도록 할 수 있습니다.
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1" AutoGenerateColumns="false">
    <Columns>
        <asp:BoundField DataField="BusinessEntityID" HeaderText="번호" />
        <asp:BoundField DataField="FirstName" HeaderText="이름" />
        <asp:BoundField DataField="LastName" HeaderText="성" />
    </Columns>
</asp:GridView>
▶ <코드 1-2>

GridView 의 AutoGenerateColumns 속성을 false 로 설정하면 데이터 소스의 스키마와 일치하는 컬럼을 자동으로 생성하는 것을 막게되고 다시 Columns 객체를 사용하여 GridView에 원하는 컬럼을 생성합니다.

마지막으로 BoundField 에서는 DataField 속성을 통해 데이터 소스의 컬럼과 일치하는 속성이나 컬럼명을 명시하면 비로소 관련 데이터를 화면에 표시하게 됩니다.


이때 데이터소스의 데이터집합이 GridView에 바인딩되는 순간을 잡아내려면 OnDataBounding 이벤트를 사용하면 됩니다.(반면 바인딩이 완료되는 시점에는 OnDataBound 이벤트가 발생합니다.)

참고로 GridView가 데이터를 표시하기 위해 Row를 생성하는 경우 OnRowCreated 이벤트가 발생하는데 이벤트를 활용하면 특정 Row의 스타일등을 Runtime 단에서 조정할 수 있으며
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1" OnRowCreated="GridView1_RowCreated"></asp:GridView>
protected void GridView1_RowCreated(object sender, GridViewRowEventArgs e)
{
    e.Row.BackColor = System.Drawing.Color.SkyBlue; //생성되는 Row의 배경색을 SkyBlue로 지정
}

OnRowDataBound 이벤트는 OnRowCreated 이벤트 생성 후 실제 데이터가 바인딩될때 발생하는 이벤트로서 바인딩데이터를 확인해 보는 것이 가능합니다. 이 특징을 잘 활용하면 표시될 데이터가 특정 값을 가진 경우에 대해 별도의 처리를 진행할 수 있습니다.

<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1" OnRowDataBound="GridView1_RowDataBound"></asp:GridView>
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.DataItem != null) {
        DataRowView drv = (DataRowView)e.Row.DataItem;

        if (drv["MiddleName"] == DBNull.Value)
            e.Row.BackColor = System.Drawing.Color.Red; //MiddleName 필드의 값이 Null 인 경우 해당 Row의 색을 붉은색으로 표시함
    }
}
 EmptyData

GridView 에 제공되는 Data Source 는 경우에 따라 표시할 데이터 내용을 가지고 있지 않는 경우가 있습니다. 날짜에 따라, 또는 검색조건에 따라 기타 여러가지 이유로 일치하는 항목이 없는 경우등을 예로 들 수 있겠습니다. GridView 는 표시할 내용이 아무것도 없는 경우에는 기본적으로 어떠한 내용도 표시하지 않습니다.

그렇다 하여 실제 사용자에게 덩그러니 빈 화면만 보여주게 되면 실제 내용이 없어서 표시가 안되는것인지 아니면 어떤 오류상황에 의해 데이터를 표시하지 않는 것인지 혼동을 줄 수 있으므로 적당한 안내멘트를 대신 뿌려줄 필요가 있습니다. GridView는 이런 경우에 대한 해결책으로 두가지 방법을 사용할 수 있습니다.

그 중 첫번째 방법은 EmptyDataText 속성을 사용하는 것입니다.
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1" EmptyDataText="<font color='red'>표시할 내용 없음</font>"></asp:GridView>
▶ <코드 1-3>

EmptyDataText 는 html 태그를 포함한 간단한 문자열을 값으로 지정할 수 있으며 아무런 내용도 표시할 수 없을때 새로운 DataRow 를 생성하여 EmptyDataText 에 할당한 값을 대신 표시하게 됩니다. 두번째 방법은 GridView안에 EmptyDataTemplate 이라는 컨트롤 템플릿을 사용하는 방법으로서
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1">
    <EmptyDataTemplate>
        <table border="5"><tr><td>표시할 내용 없음</td></tr></table>
    </EmptyDataTemplate>
</asp:GridView>
▶ <코드 1-4>

이때는 다소 복잡한 HTML 내용이나 심지어 ASP.NET 컨트롤 까지도 포함한 내용을 직접 작성할 수 있게 되며 내용이 제법 방대하고 복잡한 경우에 사용할 수 있는 방법에 해당합니다. 이 처럼 EmptyDataTemplate 은 임의로 생성되는 Row를 완벽하게 커스터마이징 할 수 있는 확장성을 제공합니다.

참고로 데이터 전체가 아닌 특정 컬럼의 값에 대해서 개별적으로 NULL 이나 빈값에 대응하는 표시내용을 설정해야 하는 경우가 있는데 이 때는 <코드 1-5>에서 처럼 BoundField 에서 직접 처리하기를 원하는 내용을 지정해 줘야 합니다.
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1" AutoGenerateColumns="false">
    <Columns>
        <asp:BoundField DataField="BusinessEntityID" />
        <asp:BoundField DataField="FirstName"  />
        <asp:BoundField DataField="LastName" />
        <asp:BoundField DataField="Title" NullDisplayText="N/A" />
    </Columns>
</asp:GridView>
▶ <코드 1-5>

<코드 1-5>에서는 Title 열값에 Null 이 존재하는 경우 NullDisplayText 속성을 통해 비어있는 내용대신 'N/A'로 표시할 수 있게 하였습니다.

 데이터 정렬 (SortExpression)

GridView 는 기본적으로 특정 컬럼을 오름차순이나 내림차순으로 정렬할 수 있도록 하는 기능을 제공합니다. 이 기능은 단지 GridView 의 AllowSorting 속성을 true로 설정하기만 하면 됩니다.
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1" AllowSorting="true"></asp:GridView>

이 설정을 거치고 나면 GridView Header 부분에 링크가 걸린것을 확인할 수 있으며 이 링크를 반복해서 클릭하면 해당 컬럼에 대한 오름차순/내림차순 정렬을 순환하여 표시하게 됩니다.


만일 정렬대상 컬럼이 2개 이상이라면 GridView 의 Sorting 이벤트를 통해 직접 정렬대상을 지정할 수 있습니다.
protected void GridView1_Sorting(object sender, GridViewSortEventArgs e)
{
    string oldSE = GridView1.SortExpression;
    string newSE = e.SortExpression;

    if (oldSE.Trim() != string.Empty)
        e.SortExpression = newSE + "," + oldSE;
    else
        e.SortExpression = newSE;
}
▶ <코드 2-1>

<코드 2-1>은 데이터 정렬시 발생하는 Sorting 이벤트에서 이전 정렬식(이전 정렬 컬럼;oldSE)의 내용을 가져와 새로운 정렬식(현재 정렬 컬럼;newSE)을 콤마(,)로 구분하여 결합한 뒤 실제 정렬을 수행하는데 필요한 e.SortExpression 속성에 지정하여 다중컬럼을 대상으로 정렬을 수행할 수 있도록 하였습니다.

여기서 oldSE 는 현재가 아닌 이전에 정렬된 식을 가져오는 변수로 GridView에서 데이터 출력 후 처음으로 데이터를 정렬하기 위해 GridView의 Header 링크를 클릭한 경우라면 이 변수는 비어있게 됩니다. 예를 들어 처음 FirstName 을 클릭하여 정렬을 시도한 경우라면 oldSE 는 공백, newSE 는 FirstName 값을 갖게 되며 이 후 다시 LastName 을 클릭했을 때 oldSE 는 FirstName 을 newSE 는 LastName 값을 가지게 됩니다.

예제에서 보시는 바와 같이 e.SortExpression 을 잘만 활용하면 단독이나 다수개의 컬럼을 대상으로 정렬을 지정할 수 있고 아예 공백을 대입하여 Sort 자체를 무력화 할 수도 있습니다.

참고로 <코드 2-1>에서 Sorting 처리의 방법을 알아보기 위해 OnSorting 이벤트를 적용하였는데 데이터가 정렬되고 난 직후의 이벤트라면 OnSorted 이벤트를 사용할 수도 있습니다.

 페이징(Paging)

GridView 에 페이징을 구성하려면 AllowPaging 속성을 true 로 직접 설정하거나 컨트롤의 스마트태그에서 Enable Paging 부분을 체크하면 됩니다.
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1" AllowPaging="true"></asp:GridView>
 
GridView 의 페이징기능은 기본적으로 10페이지씩 분할하게 되며 페이지를 이동할 수 있는 숫자는 하단 왼쪽에 위치하게 됩니다.

PageSize 속성을 이용하면 기본 10페이지로 나누는 범위를 조정할 수 있으며 PagerSettings-Mode 를 사용하면 페이지이동 숫자(기본값)이외에 맨처음, 마지막 등의 점프링크를 페이징에 추가할 수도 있거나 숫자를 제거하고 이전, 다음으로만 이동이 가능하도록 제한 할 수도 있습니다.
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1" AllowPaging="true" PageSize="20" PagerSettings-Mode="NumericFirstLast"></asp:GridView>

하단에 표시되는 페이징 부분을 좀더 시각적으로 디자인하고자 한다면 PagerStyle- 로 시작하는 속성을 사용합니다. 글자의 색상이나 크기등 다양한 디자인 요소를 적용할 수 있습니다.
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1" AllowPaging="true" PagerStyle-ForeColor="Red"></asp:GridView>

페이징과 관련된 주요 이벤트로는 2개가 있는데 PageIndexChanging 과 OnPageIndexChanged 이며 페이징 전/후로 이벤트가 발생됩니다. 주로 페이징을 수행할때 이전 페이지번호등을 확인하거나 필요하지 않은 경우 페이징동작을 무력화 하는경우에 사용합니다.

 Style 지정

GridViw 는 GridView 자체에 대한 디자인을 설정할 수 있도록 많은 속성을 제공합니다. 간단하게는 Gird의 제목을 지정할 수 있는 Caption 속성에서 HeaderStyle- 이나 FooterStyle- 으로 Header와 Footer 의 전경색및 글자색, 크기등 Grid의 다양한 스타일을 지정할 수 있습니다. 또한 경우에 따라 ShowHeader 나 ShowFooter 로 제목부분을 보이거나 보이지 않도록 하는 것도 가능합니다.

AlternatingRowStyle- 은 Grid의 짝수행에 대한 개별적인 스타일지정을, EditRowStyle- 은 Grid가 편집모드일때 해당 행에 대한 스타일 지정을 의미합니다. EmptyDataRowStyle- 은 Grid의 특정 Row에 표시할 내용이 없을 경우의 스타일을, SelectedRowStyle 선택상태에 있는 Row에 대한 스타일에 해당하며 PagerStyle- 로 Gird의 페이징 부분을 디자인할 수 있고 RowStyle- 로 Gird Row 에 대한 전체적인 부분을 다룰 수 있습니다.
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1" AllowPaging="True" AlternatingRowStyle-BackColor="AliceBlue" PagerSettings-Mode="NextPreviousFirstLast" PagerSettings-FirstPageText="처음" PagerSettings-LastPageText="마지막"></asp:GridView>

 Column 커스터마이징

GridView 가 데이터 소스(Data Source)의 데이터를 표시할때 컬럼(Column)이 자동으로 생성되는 경우라면 기본적으로 BoundField 를 사용하게 됩니다. BoundField 는 데이터 소스의 내용을 문자열로서 취급하는데 다만 데이터가 bool 타입인 경우라면 CheckBoxField 로 대신합니다.

문제는 단순히 데이터소스내용을 그대로 문자열로서 표시하는 경우가 그렇게 흔하지 않다는 것입니다. 더군다나 데이터 소스(select query 에 기반한)에 드러난 모든 컬럼을 그대로 생성하여 표시하는 경우 대부분은 특정 컬럼을 가공하여 출력하는 경우가 많기 때문에 컬럼 자동생성이 그렇게 유용하게 쓰이는 경우는 거의 없습니다.

따라서 GridView 사용시 Column 에 대한 커스터마이징을 해야 하는 경우가 많으며 이때 문자열대신 경우에 따라 연결가능한 하이퍼링크나 버튼, 체크박스형태로 출력하는 것도 가능합니다.

▶ <그림 3-1>

<그림 3-1>은 GirdView 의 Column을 편집하기 위한 화면을 보여주고 있습니다. 이 화면은 GridView 의 스마트태그를 통해 'Edit Columns' 항목을 선택한 경우이며 Add New Column 항목을 클릭하면 새로운 필드 추가를 위한 옵션을 따로 설정하고 즉시 필드를 추가할 수 있습니다.

수정하거나 추가가능한 필드 중 대부분은 이름만 봐도 어떤 필드를 의미하는지 대충 잠작할 수 있으나 몇가지 필드만 확인해보고자 합니다. 우선 BoundField 는 데이터 소스의 데이터값을 그대로 표시하는 필드이며 필드를 자동으로 생성하는 경우 GridView에 만들어지는 기본필드에 해당합니다. CommandField 는 GridView 의 데이터를 수정, 삭제하는등의 동작에 필요한 명령필드를 의미하며 TemplateField 는 사용자가 임의로 필드의 형식을 재정의 하는데 사용됩니다.

필드 추가 방법을 알아보기 위해 <그림 3-2>와 같이 HyperLinkField 를 임의로 생성해 보겠습니다. 이 필드의 목적은 사용자가 추가되는 컬럼에 표시된 링크를 클릭하는 경우 특정 ID값에 관한 인물의 상세정보를 볼 수 있다고 가정한 것입니다.

▶ <그림 3-2>

새로 추가되는 필드의 Header 제목은 'Detail Person'으로 하고 보여질 내용은 '상세정보 - ' 로 설정하였습니다. 뒤에 {0} 부분은 'LastName' 이라는 데이터 소스의 컬럼을 바인딩하여 '상세정보 - Duffy' 와 같은 형태로 보여질 것입니다.

사용자가 HyperLinkField 를 클릭했을때 연결될 사이트로는 'http://localhost/person_detail.aspx' 이며 id 스트링값으로 BusinessEntityID 컬럼의 데이터를 바인딩하여 전달하도록 하였습니다.


물론 스마트태그를 통한 설정대신 아래와 같이 직접 태그를 작성할 수도 있습니다.
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1" AllowPaging="True">
    <Columns>
        <asp:HyperLinkField DataNavigateUrlFields="BusinessEntityID" DataNavigateUrlFormatString="http://localhost/person_detail.aspx?id={0}" DataTextField="LastName" DataTextFormatString="상세정보 - {0}" HeaderText="Detail Person" />
    </Columns>
</asp:GridView>
참고로 DataNavigateUrlFields 에는 2개 이상의 열을 지정할 수 있는데 이 경우 각 열은 콤마(,)로 구분하면 됩니다. DataNavigateUrlFormatString 에서는 {0}...{1} 과 같은 형식으로 지정하면 DataNavigateUrlFields에 구분된 각 열이 순서대로 바인딩될 것입니다.

다만 예제에서 사용된 DataTextField 의 경우에는 다중 열지정이 불가능합니다. 꼭 필요하다면 Select FirstName + ' ' + LastName As PersonName 과 같이 쿼리에서 2개이상의 열값을 가져와 하나의 열로 표시하는 등의 기타 다른 방법을 동원해야 합니다.

 TemplateField 사용

GridView 의 컬럼을 완벽히 재정의 하려면 TemplateField 를 사용합니다. TemplateField 는 필드의 커스터마이징을 위해 대략 아래 6개 템플릿 필드를 제공합니다.
 
 ItemTemplate  기본적으로 DataSource 의 아이템을 표시하기 위한 템플릿입니다.
 AlternatingItemTemplate  교차 아이템을 표시하기 위한 템플릿입니다. 여기서 말하는 교차는 예를 들어 처음행에는 내용이 있다가 다음행에는 없고 다시 다음행에는 내용이 들어가는 식의 동작을 의미합니다.
 EditItemTemplate  GridView가 편집상태에 들어갔을때 내용을 표시하기 위한 템플릿입니다.
 InsertItemTemplate  GridView가 데이터 추가상태에 들어갔을때 내용을 표시하기 위한 템플릿입니다.
 HeaderTemplate  템플릿필드의 헤더부분을 표시하는 템플릿입니다.
 FooterTemplate  템플릿필드의 푸터부분을 표시하는 템플릿입니다.
▶ <표 1-1>


TemplateField 를 사용해보기 위해 이전에 같은 방법으로 TemplateField 을 GridView에 추가합니다. TemplateField 은 <표 1-1>의 템플릿을 포함하는 컨테이너로서 제공됩니다. 추가된 해당 템플릿을 편집하기 위해 GirdView에서 마우스 오른쪽 버튼을 눌러 Edit Template 하위의 Column[0] - Custom(방금전 추가한 TemplateField) 을 선택하거나


GridView 의 스마트태그에서 'Edit Template' 를 선택합니다.


그리고 위에서 언급한 템플릿 항목중 원하는 항목을 선택하여 TemplateField 에 추가합니다.


아래는 ItemTemplate 을 추가하여 새로운 내용을 표시하도록한 예제입니다.
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1" AllowPaging="True">
    <Columns>
        <asp:TemplateField HeaderText="Custom">
            <ItemTemplate>
                <table>
                    <tr>
                        <td><asp:Label ID="Label1" runat="server" Text='<%# String.Format("{0} - {1}", Eval("FirstName"), Eval("LastName")) %>'></asp:Label></td>
                        <td><asp:Button ID="Button1" runat="server" Text="확인" /></td>
                    </tr>
                </table>
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>
▶ <코드 4-1>

TemplateField 에 Table 태그를 추가하고 해당 Table 의 각 Cell 에 Label 과 Button 컨트롤을 배치하였습니다. 이 예제는 내용상 큰 의미가 없으나 TemplateField 에 단순한 태그뿐만 아니라 컨트롤까지도 포함하여 다양한 처리를 구현할 수 있음을 보여주고 있습니다.


참고적으로 <코드 4-1>에 사용된 Eval 은 바인딩되는 데이터에 접근하기 위한 수식입니다.

 GridView 수정

GridView 컨트롤을 사용하면 사용자에게 데이터를 직접 수정할 수 있도록 하는 기능을 손쉽게 제공할 수 있습니다.

GridView가 SqlDataSource 컨트롤과 같이 사용되는 경우 데이터 조작작업이 가능하게 하기 위해서는 이 두개의 컨트롤 모두 필요한 설정 작업이 선행되어야 합니다. 오해하지 말아야 할것은 GridView를 사용한다고 해서 반드시 SqlDataSource 를 사용해야 하는 것은 아니며 이 두개의 컨트롤이 반드시 연결되어야만 특정 데이터에 대한 추가/수정 작업이 가능한것은 아닙니다.

우선 GridView의 데이터 수정 작업 처리를 위해서 SqlDataSource 컨트롤에 대해 <코드 5-1> 과 같은 설정이 필요합니다. 이 작업은 SqlDataSource 설정마법사나 아니면 직접 마크업을 작성하는 방법으로 처리할 수 있습니다.
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:new_connection %>" SelectCommand="SELECT [AddressID], [AddressLine1], [City] FROM [Person].[Address] ORDER BY [AddressID]" UpdateCommand="UPDATE [Person].[Address] SET [AddressLine1] = @AddressLine1, [City] = @City WHERE [AddressID] = @AddressID">
</asp:SqlDataSource>
▶ <코드 5-1>

참고로 <코드 5-1> 에서 사용된 데이터 소스는 AdventureWorks2012 DB의 Person.Adress 이며 AddressID와 AddressLine1, City 를 불러오고 이들에 대해 Update(수정) 명령을 처리하도록 Command 속성으로 Update Query 를 할당하였습니다.

Query 에 보면 @AddressLine1, @City 와 같은 것을 볼 수 있는데 GridView 에서 데이터가 처리될때 어떤 데이터가 올 수 있는지를 나타내고 있습니다. 물론 ControlParameter 나 혹은 QueryStringParameter 등 별도의 Paramter 구성을 통해서 직접 Paramter의 인수값을 지정하는 것도 가능합니다.

이것으로 SqlDataSource 에 필요한 작업은 마무리되었습니다. 생각보다 굉장히 간단하는 것을 알 수 있습니다. 이제 GridView 컨트롤을 수정하여 데이터의 Update 기능을 부여하도록 하겠습니다.
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1" AllowPaging="True" AutoGenerateEditButton="true"></asp:GridView>
▶ <코드 5-2>

GridView는 SqlDataSource 컨트롤을 설정하는 것보다 더 간단합니다. AutoGenerateEditButton 속성에 true 값을 주기만 하면 GridView에 자동적으로 Update에 필요한 기능이 추가됩니다.


자동으로 생성된 Edit 링크를 클릭하면 해당 Row에 대한 편집상태로 들어가게 되고


임의의 값을 입력하고 Update 를 클릭하면 수정한 데이터가 반영됩니다. 그런데 좀 이상하지 않습니까? Person.Address 테이블의 AddressID는 키값입니다. 사용자가 AddressID 1 번인 Row를 수정하려고 할때 만약 AddressID 입력칸에 다른 값을 집어넣으면 어떻게 될까요? 의도한 경우든 아니든 입력한 값에 해당하는 AddressID 값의 데이터가 변경되어버립니다.

물론 사용자가 데이터 변경시 정확한 규칙을 알고 적절히 GridView를 사용할 수 있지만 그렇다 하더라도 중요한 정보인 Key값은 바꿀 수 없도록 해야 합니다. 이를 위해 GridView안에 DataKeyNames="AddressID" 속성을 추가합니다. 그러면 더이상 지정된 열에 해당하는 값은 바꿀 수 없게 됩니다.
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1" AllowPaging="True" DataKeyNames="AddressID">
참고로 Key로 설정할 열이 2개 이상이면 각 컬럼을 콤마(,)로 구분하여 지정하면 되고 혹시 GridView 의 열이 자동생성이 아닌 직접 BoundField 요소를 사용해 출력되는 경우라면 다음과 같이 해당 BoundField 에 ReadOnly 속성을 설정하면 됩니다.
<asp:BoundField DataField="AddressID" ReadOnly="True" />

GridView 의 데이터 편집기능 추가를 위해 사용한 AutoGenerateEditButton 이외에 GridView 안에 직접 CommandField 요소를 추가하여 같은 기능을 부여할 수도 있습니다.
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1" AllowPaging="True">
    <Columns>
        <asp:CommandField ShowHeader="true" HeaderText="수정" ShowEditButton="true" />
    </Columns>
</asp:GridView>
CommandField 를 사용하면 단순한 Link 이외에 버튼이나 이미지등 다양한 방법으로 사용자에게 데이터 편집기능을 제공할 수 있으며 Edit 뿐만 아니라 Cancel, Delete, Insert, Select 등 다른 기능을 수행할 수 있는 방법을 사용자에게 제공할 수 있습니다.

이전에 TemplateField 를 설명할때 EditItemTemplate 을 거론한적이 있습니다. EditItemTemplate 은 GridView 가 Edit 상태로 접어들때 표시될 내용을 담는 템플릿인데 GridView 의 Update 처리과정을 설명드리면서 EditItemTemplate 의 구체적인 역활에 대한것도 같이 확인해 보도록 하겠습니다.

EditItemTemplate 이 주로 사용되는 목적은 사용자가 GridView의 데이터 내용을 업데이트 할때 입력가능한 데이터에 맞는 입력방식을 제공하기 위함입니다. 예를 들어 Person.Address 테이블의 City 컬럼에 들어갈 수 있는 값이 Bothell, Portland, Seattle 세가지 뿐이라고 가정한다면 GridView 가 편집상태(업데이트)에 들어갔을때 City 입력방식으로 TextBox 형태를 제공하는건 맞지 않을 수 있습니다. TextBox 로는 Bothell, Portland, Seattle 이외에 다른 값의 입력을 막기가 까다로워질 수 있기 때문인데 그래서 이런 경우는 TextBox 형태보다는 DropDownList 와 같은 요소를 제공하여 Bothell, Portland, Seattle 이 세개 항목중 하나를 선택하도록 하는 것이 훨씬 쉬울 수 있습니다.
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1" AllowPaging="True">
    <Columns>
        <asp:CommandField ShowHeader="true" HeaderText="수정" ShowEditButton="true" />
        <asp:TemplateField HeaderText="City">
            <EditItemTemplate>
                <asp:DropDownList ID="DropDownList1" runat="server">
                    <asp:ListItem Value="Bothell">Bothell</asp:ListItem>
                    <asp:ListItem Value="Portland">Portland</asp:ListItem>
                    <asp:ListItem Value="Seattle">Seattle</asp:ListItem>
                </asp:DropDownList>
            </EditItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>
▶ <코드 5-3>

<코드 5-3> 은 TemplateField 요소를 추가하고 하위에 EditItemTemplate 요소를 포함하고 있는 예제를 보여주고 있습니다. 여기에 EditItemTemplate 은 다시 DropDownList 컨트롤을 포함하고 있으므로 GridView 가 Edit 모드로 들어가면 해당 DropDownList 컨트롤이 표시될 것입니다.

▶ <그림 5-1>

<그림 5-1> 을 보면 City 컬럼이 2개가 생성되어 있음을 볼 수 있는데 사실 이 상태로도 Update 동작을 수행시킬 수는 있으나 같은 내용의 컬럼이 불필요하게 보여지고 있으므로 GridView 의 컬럼내용을 재정의 하도록 하겠습니다.
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1" AutoGenerateColumns="false" AllowPaging="True">
    <Columns>
        <asp:CommandField ShowHeader="true" HeaderText="수정" ShowEditButton="true" />
        <asp:BoundField HeaderText="AddressID" DataField="AddressID" />
        <asp:BoundField HeaderText="AddressLine1" DataField="AddressLine1" />
        <asp:TemplateField HeaderText="City">
            <ItemTemplate><%# Eval("City") %></ItemTemplate>
            <EditItemTemplate>
                <asp:DropDownList ID="DropDownList1" runat="server">
                    <asp:ListItem Value="Bothell">Bothell</asp:ListItem>
                    <asp:ListItem Value="Portland">Portland</asp:ListItem>
                    <asp:ListItem Value="Seattle">Seattle</asp:ListItem>
                </asp:DropDownList>
            </EditItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>
▶ <코드 5-4>

GridView의 자동컬럼생성을 취소하고 BoundField 를 추가하여 다소 수동적이지만 원하는 컬럼만을 표시하도록 하였습니다.

▶ <그림 5-2>

여기서 한가지 더 팁을 설명드리자면 City 열의 DropDownList 로 항목이 표시될때 무조건 첫번째 항목부터 표시되는 것이 아니라 현재 Row 에 바인딩된 City 값이 우선적으로 선택된 상태에 있게 하려면 아래와 같이 OnRowDataBound 이벤트를 정의하여 해당 이벤트 안에 원하는 기능을 구현해 넣도록 합니다.
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1" AutoGenerateColumns="false" AllowPaging="True" OnRowDataBound="GridView1_RowDataBound">
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowState == DataControlRowState.Edit){
        System.Data.DataRowView drv = (System.Data.DataRowView)e.Row.DataItem;
        DropDownList ddl = (DropDownList)e.Row.Cells[3].FindControl("DropDownList1");
        ListItem li = ddl.Items.FindByValue(drv["city"].ToString());
        li.Selected = true;
    }
}
RowDataBound 이벤트에서는 현재 Row의 상태가 Edit 모드인지 확인(참고로 RowState 는 동시에 2가지 이상의 상태로 있을 수 있는데 이 경우를 정확히 확인하려면 e.Row.RowState == (DataControlRowState.Alternate | DataControlRowState.Edit) 처럼 조건절을 수정해야 합니다.) 하고 해당 Row 에 DropDownList 컨트롤 요소를 가져와 바인딩된 city 값에 해당하는 ListItem 을 추출합니다. 그리고 추출된 ListItem 을 선택상태로 설정함으로서 사용자가 Edit 를 눌러 편집상태로 들어가면 현재 Row의 City 값이 DropDownList 에 바로 선택상태로 나타나게 됩니다.

여기까지 DropDownList 에 값을 사용자가 직접 선택하여 입력할 수 있게끔 하고 나면 실제 DropDwonList 선택값이 DB 에 반영되도록 하는 기능을 부여해야 하며 이 동작은 GridView 의 OnRowUpdating 이벤트를 통해 이루어 집니다.
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1" AutoGenerateColumns="false" AllowPaging="True" OnRowUpdating="GridView1_RowUpdating">
protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
    GridViewRow gvr = this.GridView1.Rows[this.GridView1.EditIndex];
    DropDownList ddl = (DropDownList)gvr.Cells[3].FindControl("DropDownList1");
    e.NewValues["city"] = ddl.SelectedValue;
}
RowUpdating 이벤트에서는 현재 편집중인 Row에 있는 DropDownList 컨트롤의 선택값을 가져와 GridView 의 NewValues Collection (수정 후 실제 DB에 업데이트하는 값들) 중 필요한 열(여기서는 city)에 해당하는 값을 대입함으로서 실질적인 Update가 이루어 지도록 하였습니다.

여기까지 GridView 를 통한 Update 처리과정을 알아보았는데 GridView 에서 데이터의 업데이트 동작을 수행하는 것만큼 중요한 것이 하나 남았습니다. 업데이트 도중 발생할 수 있는 오류를 감지하고 적절하게 대응하는 것이 그것입니다. GirdView 에서 업데이트 도중 발생할 수 있는 오류는 OnRowUpdated 이벤트를 통해 처리할 수 있습니다.
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1" AllowPaging="True" OnRowUpdated="GridView1_RowUpdated">
    <Columns>
        <asp:CommandField ShowHeader="true" HeaderText="수정" ShowEditButton="true" />
    </Columns>
</asp:GridView>
▶ OnRowUpdated 설정
protected void GridView1_RowUpdated(object sender, GridViewUpdatedEventArgs e)
{
    if (e.Exception != null) {
        e.ExceptionHandled = true;
        Response.Write(e.Exception.Message);
    }
}
Update 도중 오류가 생기면 Exception 예외가 발생하고 이 값이 Null 인지를 확인함으로서 오류 발생여부를 판단합니다. 오류가 발생하면 Message 속성을 통해 오류내용을 표시하도록 했는데 중요한 것은 e.ExceptionHandled = true; 부분입니다. 이것은 오류를 직접 제어하겠다는 의미를 가지고 있는데 이러한 과정을 거치지 않으면 .NET Framework 는 HTTP 500 등의 오류페이지를 직접 띄우기 때문에 Response.Write(e.Exception.Message); 처럼 작성하여도 해당 코드의 처리결과를 확인하기가 어렵게 됩니다.

 GridView 삭제

GridView 의 데이터를 삭제하는 작업은 위에서 설명드린 수정작업보다 훨씬 간단합니다. 우선 데이터를 변경할때와 같은 방법으로 GridView에 AutoGenerateDeleteButton 속성을 설정하고
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1" AllowPaging="True" AutoGenerateDeleteButton="True" DataKeyNames="BusinessEntityID"></asp:GridView>
SqlDataSource 컨트롤에도 삭제관련 DeleteCommand 속성을 설정하기만 하면 됩니다.
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:new_connection %>" SelectCommand="SELECT * FROM [Person].[PersonPhone]" DeleteCommand="DELETE FROM [Person].[PersonPhone] WHERE [BusinessEntityID] = @BusinessEntityID"></asp:SqlDataSource>

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] DetailsView  (1) 2014.06.20
[ASP.NET] LinqDataSource - 데이터 동시성 (Data Concurrency)  (2) 2014.06.12
[ASP.NET] GridView  (3) 2014.06.11
[ASP.NET] FormView  (0) 2014.06.10
[ASP.NET] web.config 에 저장된 연결정보 다루기  (0) 2014.06.09
[ASP.NET] SiteMapDataSource  (0) 2014.05.28
3 0
Programming/.NET
FormView 는 데이터 소스로부터 하나의 레코드정보를 표시하고 데이터 추가, 편집및 삭제가 가능한 컨트롤로서 DetailsView 와 비슷한 기능을 수행합니다. 하지만 화면에 표시되는 정형화된 레이아웃이 없고 개발자가 직접 템플릿안에서 레이아웃을 구성해야 합니다.

귀찮은 단점이 될 수 있는 반면 완벽하게 레이아웃을 임의로 구성할 수 있다는 점에서 그 만큼 화면구성에 대한 자유로움이 존재합니다.


▶ <그림 1-1>

그림 1-1 은 AdventureWorks2012 샘플데이터베이스의 Person.PersonPhone 테이블에서 하나의 레코드를 표시하기위해 작성된 ItemTemplate 형태를 보여주고 있습니다. ItemTemplate 은 특정 테이블에서 레코드를 표시하기 위한 기본적인 템플릿이며 이 템플릿안에서 레이아웃이 구성되는 것입니다.
<asp:FormView ID="FormView1" runat="server" DataSourceID="SqlDataSource1">
    <ItemTemplate>
        <table border="1">
            <caption>Person Phone</caption>
            <tr>
                <th>BusinessEntityID</th>
                <th>PhoneNumber</th>
                <th>PhoneNumberTypeID</th>
                <th>ModifiedDate</th>
            </tr>
            <tr>
                <td><asp:Label ID="Label1" runat="server" Text='<%# Bind("BusinessEntityID") %>'></asp:Label></td>
                <td><asp:Label ID="Label2" runat="server" Text='<%# Bind("PhoneNumber") %>'></asp:Label></td>
                <td><asp:Label ID="Label3" runat="server" Text='<%# Bind("PhoneNumberTypeID") %>'></asp:Label></td>
                <td><asp:Label ID="Label4" runat="server" Text='<%# Bind("ModifiedDate") %>'></asp:Label></td>
            </tr>
        </table>
    </ItemTemplate>
</asp:FormView>
▶ <코드 1-1>

코드 1-1 은 그림 1-1 에서 ItemTemplate 에 작성된 부분을 보여주고 있으며 임의의 HTML 코드는 물론 심지어 ASP.NET 컨트롤 까지도 포함할 수 있습니다.

이러한 형태로 FormView 에서는 데이터 편집시 보여지는 EditItemTemplate, 데이터 추가시 보여지는 InsertItemTemplate 등을 정의할 수 있고, 그 밖에 Footer 나 Paging, Empty 등에 대한 템플릿도 정의할 수도 있습니다.
0 0
Programming/.NET
일반적으로 데이터 베이스 연결정보와 같은 데이터는 web.config 안에 저장하게 됩니다. 이것은 정해진 규칙은 아니지만 대부분의 경우 웹사이트안에서 연결정보에 대한 접근을 쉽게할 수 있고 관련정보의 관리또한 간단해 질 수 있기 때문입니다.
<connectionStrings>
  <add name="AdventureWorks2012ConnectionString" connectionString="Data Source=localhost;Initial Catalog=AdventureWorks2012;User ID=sa;Password=1234" providerName="System.Data.SqlClient" />
</connectionStrings>

▶ <코드 1-1>

<코드 1-1>은 web.config 의 connectionStrings 섹션에 저장된 MSSQL 서버 연결정보를 보여주고 있습니다.

만약 web.config 안에 저장된 연결정보가 상황에 따라 런타임에서 동적으로 다루어져야 하는 경우 ConnectionStringSettings 클래스를 활용하게 됩니다. 이 클래스는 web.config 파일에 저장된 연결정보 섹션에 대한 컬렉션을 담고 있는 클래스로서 web.config 안의 연결정보를 추가하거나 수정, 삭제가 가능하도록 합니다.

ConnectionStringSettings css = new ConnectionStringSettings();
css.ConnectionString = "Server=localhost;User ID=sa;Password=1234;Database=AdventureWorks2012";
css.Name = "new_connection";
css.ProviderName = "System.Data.SqlClient";

Configuration c = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
c.ConnectionStrings.ConnectionStrings.Add(css);
c.Save(ConfigurationSaveMode.Minimal);

▶ <코드 1-2>

<코드 1-2>는 web.config 파일안에 연결정보를 추가하는 내용입니다. System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration 메소드에 의해 반환된 Configuration 클래스는 web.config 안에 연결정보에 대한 컬렉션을 가지게 되며 이 클래스의 add 메소드를 호출하여 ConnectionStringSettings 클래스로 설정된 연결정보를 Configuration 클래스의 ConnectionStrings 컬렉션에 추가하게 됩니다.

또한 DB연결정보를 생성할때 SqlConnectionStringBuilder 클래스를 사용할 수 있는데 이 클래스는 연결정보문자열 자체를 강력한 타입형식으로 가져와 속성으로서 DB 연결정보를 설정할 수 있도록 합니다.

Configuration c = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
ConnectionStringSettings css = c.ConnectionStrings.ConnectionStrings["new_connection"];

SqlConnectionStringBuilder ssb = new SqlConnectionStringBuilder(css.ConnectionString);
ssb.DataSource = "192.168.0.15";
css.ConnectionString = ssb.ConnectionString;

c.ConnectionStrings.ConnectionStrings.Add(css);
c.Save(ConfigurationSaveMode.Minimal);
▶ <코드 1-3>

<코드 1-2>는 런타임에서 web.config 안에 연결정보를 수정할 수 있도록 하는 예제입니다. Configuration 클래스 에서 특정 연결정보를 가져와 SqlConnectionStringBuilder 클래스에 바인딩하고 원하는 속성(예제에서는 DataSource 속성)의 정보를 수정한 후 다시 Configuration 클래스를 통해 저장함으로서 기존의 연결정보값을 수정하는 것입니다.

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] GridView  (3) 2014.06.11
[ASP.NET] FormView  (0) 2014.06.10
[ASP.NET] web.config 에 저장된 연결정보 다루기  (0) 2014.06.09
[ASP.NET] SiteMapDataSource  (0) 2014.05.28
[ASP.NET] ObjectDataSource  (1) 2014.05.23
[ASP.NET] XmlDataSource  (0) 2014.05.13
0 0
1 2 3
블로그 이미지

클리엘