Skip to content

FoxDataService Class

Fox Data Service 는 FoxDataService 클래스에 의해 제공되는 데이터 액세스 서비스입니다. FoxDataService 클래스는 Fox Query 를 사용하여 데이터베이스를 액세스하는 기능을 캡슐화한 클래스입니다. 클라이언트는 호출할 Fox Query 의 ID 와 매개변수를 포함하는 FoxDataRequest 객체를 매개변수로 FoxDataService 클래스의 ExecuteXXX 시리즈 메서드를 호출하여 쿼리를 실행하고 그 결과를 FoxDataResponse 객체를 통해 받을 수 있습니다.

Fox Data Service 는 단순히 Fox Query 를 실행하는 기능 뿐만 아니라 여러 쿼리를 배치로 수행하는 다중 쿼리(ExecuteMultiple), DataTable 에 기록된 여러 변경 사항(추가/수정/삭제)을 저장하는 기능(SaveDataTable), 단일 혹은 다중 쿼리에 대한 로컬/분산 트랜잭션 기능, 쿼리 성능 측정 기능, 로깅을 포함하는 다양한 진단 기능 등을 제공합니다.

Basic Usage

Fox Data Service 를 사용하기 위해서는 NeoDEEX.ServiceModel.Services 패키지를 참조해야 합니다. 이 패키지에는 Fox Data Service 와 Fox Biz Service 를 구현하는 클래스들이 포함되어 있습니다. FoxDataService 클래스는 NeoDEEX.ServiceModel.Services.Data 네임스페이스에 포함되어 있습니다.

Fox Web API 없이 직접 Fox Data Service 를 사용하는 경우, FoxDataService 클래스의 인스턴스를 생성하여 ExecuteXXX 시리즈 메서드를 호출할 수 있습니다. 다음 코드는 ASP.NET Core Razor 페이지에서 Fox Data Service 를 사용하여 orders.foxml 파일의 get_all_orders_with_details 쿼리를 호출하여 결과를 HTML 로 렌더링하는 예를 보여줍니다.

@{
    ViewData["Title"] = "Home page";

    FoxDataRequest dataRequest = new("orders.get_all_orders_with_details");
    FoxDataService dataService = new();
    FoxDataResponse dataResponse = dataService.ExecuteDataSet(dataRequest);
    DataTable ordersTable = dataResponse.DataSet.Tables[0];
}
<div>
    ......
    <tbody>
      @foreach (DataRow row in ordersTable.Rows)
      {
        <tr>
          <td>@row["order_id"]</td>
          ......
        </tr>
      }
    </tbody>
    ......
</div>

서비스 객체 생성

FoxDataService 클래스는 매개변수가 없는 디폴트 생성자만을 제공하지만 대신 Fox Data Service 의 작동 방식을 설정하는 다양한 public 속성들을 제공합니다. Fox Data Service 가 ASP.NET Web API 나 WCF, gRPC 와 같은 다양한 통신 서비스에 의해 사용되며 개발자가 직접 FoxDataService 클래스의 인스턴스를 생성하는 경우가 많지 않기 때문입니다. 대신 구성 설정 파일(neodeex.config.json 파일)에서 이들 public 속성들의 기본값을 설정할 수 있습니다.

  • EnableDiagnostics 속성

    FoxDataService 클래스가 제공하는 다양한 진단 기능들을 켜거나 끌 수 있는 속성입니다. 진단 기능에는 쿼리 수행 시간 측정, 로그 반환, 상세한 예외 정보, 로그 ID 등이 포함됩니다. 성능 로그, DB 프로파일 로그를 기록하지 않도록 하는 설정(SuppressWritePerfLog)은 이 속성과 무관하게 작동합니다. 상세한 내용은 성능 로깅과 DB 프로파일 로깅을 참조하십시요. 아무런 구성 설정이 없는 경우, 이 속성의 기본값은 false 입니다.

  • LoggerName 속성

    FoxDataService 클래스가 로그를 기록할 때 사용할 로거의 이름을 지정하는 속성입니다. 이 속성은 EnableDiagnostics 속성이 true로 설정된 경우에만 적용됩니다. 아무런 구성 설정이 없는 경우 이 속성의 기본값은 NeoDEEX.ServiceModel.Data.FoxDataService 입니다.

  • EnableDetailedDbProfile 속성

    FoxDataService 클래스의 ExecuteXXX 시리즈 메서드들은 쿼리를 수행하고 결과를 반환할 때 DB 프로파일 정보를 FoxDataResponse 객체에 반환할 수 있습니다(FoxDataRequestDiagnostics.DbProfileInfo 설정). DB 프로파일 정보에는 쿼리에 사용된 SQL 문장과 매개변수 값 등 민감한 정보가 포함될 수 있습니다. 따라서 이 속성이 true로 설정된 경우에만 모든 정보를 반환하며 false로 설정된 경우에는 민감한 정보가 제외된 DB 프로파일 정보만 반환합니다. 아무런 구성 설정이 없는 경우 이 속성의 기본값은 false 입니다.

    개발 서버의 경우 이 속성을 true로 설정하여 DB 프로파일 정보를 활용한 진단을 수행할 수 있지만, 운영 서버의 경우 이 속성을 false로 설정하여 민감한 정보가 노출되는 것을 방지하는 것이 좋습니다.

    EnableDiagnostics 속성이 false로 설정된 경우에는 이 속성의 값과 무관하게 DB 프로파일 정보가 반환되지 않습니다.

  • EnablePerfLog 속성

    FoxDataService 클래스는 쿼리를 수행하는데 소요되는 시간을 측정하여 로그에 기록할 것인지 여부를 지정하는 속성입니다. 이 속성이 true로 설정된 경우, 성능 로그가 PerfLoggerName 속성이 지정하는 로거에 기록합니다. 아무런 구성 설정이 없는 경우 이 속성의 기본값은 false 입니다.

  • PerfLoggerName 속성

    FoxDataService 클래스가 성능 로그를 기록할 때 사용할 로거의 이름을 지정하는 속성입니다. 이 속성은 EnablePerfLog 속성이 true로 설정된 경우에만 적용됩니다. 아무런 구성 설정이 없는 경우 이 속성의 기본값은 NeoDEEX.ServiceModel.Data.FoxDataService.Performance 입니다.

구성 설정

Fox Data Service 에 대한 구성 설정은 neodeex.config.json 파일의 최상위 "dataService" 섹션에서 다음과 같이 설정할 수 있습니다.

{
  "dataService": {
    "commandTimeout": null,
    "transactionTimeout": 60,
    "diagnostics": {
        "enable": false,
        "loggerName": "NeoDEEX.ServiceModel.Data.FoxDataService",
        "detailedDbProfile": false
    },
    "perfLog": {
        "enable": false,
        "loggerName": "NeoDEEX.ServiceModel.Data.FoxDataService.Performance"
    }
  }
}
  • commandTimeout 속성

    commandTimeout 속성은 Fox Data Service 가 쿼리를 수행할 때 사용할 기본 쿼리 타임 아웃을 초 단위로 지정하는 속성입니다. 이 속성이 설정되지 않았거나 null로 설정된 경우, 연결 문자열에 설정된 타임 아웃 값이 사용됩니다. 물론 이러한 "기본 설정 값"은 FoxDataRequest 객체의 CommandTimeout 속성에서 개별 쿼리 호출 시에 오버라이드할 수 있습니다.

  • transactionTimeout 속성

    transactionTimeout 속성은 Fox Data Service 가 트랜잭션을 시작할 때 사용할 기본 트랜잭션 타임 아웃을 초 단위로 지정하는 속성입니다. 이 속성이 설정되지 않았거나 null로 설정된 경우, 60초의 값이 사용됩니다. 물론 이러한 "기본 설정 값"은 FoxDataRequest 객체의 TransactionTimeout 속성에서 개별 쿼리 호출 시에 오버라이드할 수 있습니다.

  • diagnostics 속성

    서비스 객체 생성 항목에서 설명한 EnableDiagnostics, LoggerName, EnableDetailedDbProfile 속성은 이 diagnostics 속성의 하위 속성으로 설정할 수 있습니다. 이들 하위 속성의 이름은 각각 enable, loggerName, detailedDbProfile 입니다.

  • perfLog 속성

    서비스 객체 생성 항목에서 설명한 EnablePerfLog, PerfLoggerName 속성은 이 perfLog 속성의 하위 속성으로 설정할 수 있습니다. 이들 하위 속성의 이름은 각각 enable, loggerName 입니다.

서비스 메서드들

FoxDataService 클래스는 FoxDbAccess 클래스와 유사하게 ExecuteXXX 시리즈 메서드들을 제공합니다. ExecuteXXX 시리즈 메서드들은 하나의 쿼리를 수행하는 단일 쿼리 메서드들과 여러 개의 쿼리를 수행하는 다중 쿼리 메서드들로 나눌 수 있습니다. 단일 쿼리 메서드들은 FoxDataRequest 객체를 매개변수로 받아 하나의 쿼리를 수행하는 반면, 다중 쿼리 메서드들은 FoxDataRequestCollection 객체를 매개변수로 받아 여러 개의 쿼리를 배치로 수행하며 그 결과는 FoxDataResponseCollection 객체로 반환됩니다.

단일 쿼리 메서드들

단일 쿼리 메서드들은 하나의 FoxQuery 를 수행하는 메서드들입니다. 따라서 FoxDataRequest 객체의 QueryId 속성에 하나의 쿼리 ID 를 지정하며 매개변수는 Parameters 속성에 지정합니다. 쿼리에 사용할 데이터베이스 연결 문자열의 이름을 DatabaseName 속성에 지정할 수도 있습니다.

  • ExecuteDataSet 메서드

    FoxDataRequest 객체의 쿼리를 실행하여 결과를 DataSet 형태로 반환하는 메서드입니다. 반환된 DataSet 객체는 FoxDataResponse 객체의 DataSet 속성에 포함되어 반환됩니다. SELECT 문과 같은 결과셋을 반환하는 쿼리를 수행하는데 사용합니다.

  • ExecuteScalar 메서드

    Command 객체의 ExecuteScalar 메서드와 유사하게 FoxDataRequest 객체의 쿼리를 실행하여 결과셋의 첫 번째 행의 첫 번째 열의 값을 반환하는 메서드입니다. 반환된 값은 FoxDataResponse 객체의 ScalarValue 속성에 포함되어 반환됩니다. SELECT COUNT(*) 문과 같은 단일 값을 반환하는 쿼리를 수행하는데 사용합니다.

  • ExecuteNonQuery 메서드

    Command 객체의 ExecuteNonQuery 메서드와 유사하게 FoxDataRequest 객체의 쿼리를 실행하여 영향받은 행 수를 반환하는 메서드입니다. 반환된 영향받은 행 수는 FoxDataResponse 객체의 AffectedRows 속성에 포함되어 반환됩니다. INSERT, UPDATE, DELETE 문과 같은 데이터 변경 쿼리를 수행하는데 사용합니다.

  • Execute 메서드

    FoxDataRequest 객체의 Operation 속성 값에 따라 ExecuteXXX 시리즈 메서드들 중 하나를 호출하는 메서드입니다. Operation 속성 값이 DataSet, Scalar, NonQuery, SaveDataTable 인 경우 각각 ExecuteDataSet, ExecuteScalar, ExecuteNonQuery, SaveDataTable 메서드를 호출합니다. 이 메서드는 클라이언트가 실행할 쿼리의 유형을 동적으로 지정해야 하는 시나리오에서 유용합니다.

ExecuteMultiple 메서드

ExecuteMultiple 메서드는 FoxDataRequestCollection 객체를 매개변수로 받아 여러 개의 쿼리를 배치로 수행하는 메서드입니다. FoxDataRequestCollection 객체는 여러 개의 FoxDataRequest 객체를 포함할 수 있으며, 각 FoxDataRequest 객체는 하나의 쿼리를 나타냅니다. ExecuteMultiple 메서드는 이들 쿼리를 순차적으로 모두 수행하여 그 결과를 FoxDataResponseCollection 객체로 반환합니다. 반환된 FoxDataResponseCollection 객체는 여러 개의 FoxDataResponse 객체를 포함할 수 있으며, 각 FoxDataResponse 객체는 하나의 쿼리 수행 결과를 나타냅니다.


  • 데이터베이스 연결

SaveDataTable 메서드

SaveDataTable 메서드는 매개변수로 주어진 DataTable 객체에서 각 행의 RowState에 따라 추가/수정/삭제된 행들을 데이터베이스에 저장하는 메서드입니다. 데스크 톱 앱에서 DataTable 객체를 바인딩하여 사용자가 그리드에서 데이터를 추가/수정/삭제할 수 있도록 하는 시나리오에서 유용합니다. 데이터그리드 컨트롤에서 추가/수정/삭제된 데이터를 GetChanges 메서드를 사용하여 DataTable 객체로 가져와서 SaveDataTable 메서드에 전달하여 변경된 여러 개의 행을 한 번에 저장할 수 있습니다.

private void SaveButton_Click(object sender, EventArgs e)
{
    DataTable productDataTable = ProductGrid.DataSource as DataTable;
    DataTable changes = productDataTable?.GetChanges();

    FoxDataRequest dataRequest = new("products.save_changes");
    dataRequest.InsertQueryId = "products.insert";
    dataRequest.UpdateQueryId = "products.update";
    dataRequest.DeleteQueryId = "products.delete";
    dataRequest.DataSet = new DataSet();
    dataRequest.DataSet.Tables.Add(changes);
    dataRequest.QueryId = "products.get_all";      // 저장 후 조회에 사용할 쿼리 ID
    dataRequest.SaveMode = FoxDataSaveModes.GroupedBatchUpdate;
    dataRequest.Transaction = FoxDataTransactions.Local;
    FoxDataServiceClient client = new("api/dataservice");
    FoxDataResponse dataResponse = client.SaveDataTable(dataRequest);
    int savedRowCount = dataResponse.AffectedRows;
    MessageBox.Show($"{savedRowCount}개의 행이 저장되었습니다.");
    ProductGrid.DataSource = dataResponse.DataSet.Tables[0];
}

Note

위 예제 코드는 WinForms 데스크톱 앱에서 FoxDataServiceClient 클래스 를 활용하여 원격 Fox Web API 를 호출하는 예제 코드 입니다.

추가/수정/삭제에 사용할 쿼리 ID 는 FoxDataRequest 객체의 InsertQueryId, UpdateQueryId, DeleteQueryId 속성에 각각 지정합니다. 저장에 사용할 DataTable 객체는 FoxDataRequest 객체의 DataSet 속성에 DataSet 형태로 지정합니다.

QueryId 속성이 null 이나 빈 문자열이 아닌 경우, QueryId 속성과 Parameters 속성은 저장 후 조회(ExeucteDataSet 메서드)를 수행하는데 사용됩니다. 저장 후 조회는 SaveDataTable 메서드가 DataTable 객체의 변경된 내용을 데이터베이스에 저장한 후, 지정된 QueryId에 해당하는 쿼리를 다시 실행하여 데이터베이스에 저장된 최신 데이터를 반환하는 기능입니다. 이 기능은 클라이언트가 DataTable 객체의 변경된 내용을 데이터베이스에 저장한 후, 데이터베이스에 저장된 최신 데이터를 다시 조회해야 하는 시나리오에서 유용합니다.

SaveDataTable 메서드가 여러 행의 추가/수정/삭제를 처리하는 방식은 3가지 모드 중 하나로 지정할 수 있습니다. 이 저장 모드는 FoxDataRequest 객체의 SaveMode 속성에 FoxDataSaveModes 열거 타입을 사용하여 지정합니다.

  • LoopUpdate 모드

    SaveDataTable 메서드의 기본 저장 모드이며, DataTable 에서 변경된 행들을 그룹화하여 업데이트할 때 반복문(foreach)을 사용합니다. 삭제, 수정, 추가 순서로 변경된 행들을 처리합니다. 안정적이지만 다수의 행을 처리해야 한다면 성능이 좋지 않을 수 있습니다.

  • BatchUpdate 모드

    ADO.NET 의 DataAdapter 클래스의 Update 메서드를 사용하여 일괄 업데이트를 수행하는 저장 모드입니다. 데이터베이스 프로바이더 구현에 따라서 Update 메서드는 여러 수정사항을 배치로 처리할 수 있기 때문에 다수의 행을 처리해야 할 때 성능상 장점을 가질 수 있습니다. 하지만 DataAdapter.Update 메서드에 의존하므로 데이터베이스 프로바이더의 구현에 따라 성능 차이가 발생할 수 있으며, 데이터 저장 순서 역시 프로바이더에 따라 달라질 수 있습니다.

  • GroupedBatchUpdate 모드

    BatchUpdate 모드와 동일하게 ADO.NET 의 DataAdapter 클래스의 Update 메서드를 사용하여 일괄 업데이트를 수행하지만, LoopUpdate 모드와 같이 삭제, 수정, 추가 순서로 변경된 행들을 처리하는 저장 모드입니다. BatchUpdate 모드에 비해 안정적인 저장 순서를 보장하지만, 데이터베이스 프로바이더의 구현에 따라 성능 차이가 발생할 수 있습니다.

기본적으로 SaveDataTable 메서드는 트랜잭션을 사용하지 않으며, 저장 도중 오류가 발생하면 즉시 수행을 중단하고 반환합니다. FoxDataRequest 객체의 Transaction 속성에 트랜잭션 모드를 지정하여 트랜잭션을 사용하는 경우, 저장 도중 오류가 발생하면 전체 저장 작업이 롤백됩니다.

SaveDataTable 메서드는 저장이 성공적으로 완료된 후에 저장한 행 수를 반환합니다. 반환된 저장된 행 수는 FoxDataResponse 객체의 AffectedRows 속성에 포함되어 반환됩니다.

로깅

Fox Data Service 는 코드를 작성하지 않고 데이터베이스 액세스를 수행하기 때문에 오류가 발생한 경우 추적 및 진단이 용이하지 않습니다. 따라서 Fox Data Service 는 수행 단계마다 상세한 로그를 남깁니다.

성능 측정

트랜잭션

Summary