Skip to content

커맨드 수행

Fox DB Access 를 통해 데이터베이스에서 SQL 문장을 수행하거 저장 프로시저를 호출하기 위해서는 Execute- 시리즈의 메서드를 호출해야 합니다. Execute- 시리즈 메서드들은 내부적으로 Command 객체를 만들고 필요한 설정과 매개변수 지정을 하고 SQL 문장 혹은 저장 프로시저를 수행하고 그 결과를 반환합니다.

FoxDbAccess 클래스 및 그 파생 클래스들은 수행하고자 하는 데이터베이스 작업과 그 결과값에 따라 매우 다양한 Execute- 시리즈 메서드를 제공합니다. 매우 많은 메서드들을 빠르게 이해하는 방법으로 메서드 이름에 사용된 2 종류의 접미사를 이해하면 도움이 됩니다.

이 문서와 관련된 예제 코드는 다음 예제를 참조 하십시요.

Execute- 메서드 접미사

예를 들어 ExecuteSpDataSet 메서드는 Sp 접미사와 DataSet 접미사를 쓰는 Execute- 메서드입니다. Sp 접미사는 저장 프로시저를 수행한다는 의미의 접미사이며 DataSet 접미사는 수행결과를 DataSet 객체로 반환함을 나타내는 접미사 입니다.

수행 대상 접미사

첫번째 접미사는 Execute- 시리즈 메서드가 수행할 데이터베이스 작업을 나타냅니다.

  • -Sql- : SQL 문장을 수행합니다. 전통적인 코딩 방식으로 이야기 하자면 CommandType.Text 에 해당하는 작업을 수행합니다. 이들 메서드들은 수행할 SQL 문장을 첫번째 매개변수로 사용합니다.

    1
    2
    3
    4
    5
    using FoxDbAccess dbAccess = FoxDbAccess.CreateDbAccess();
    FoxDbParameterCollection parameters = dbAccess.CreateParamCollection();
    parameters.AddWithValue("my_column1", ...);
    parameters.AddWithValue("my_column2", ...);    
    dbAccess.ExecuteSqlNonQuery("INSERT INTO my_table...", parameters);
    
  • -Sp- : 저장 프로시저를 수행합니다. 전통적인 코딩 방식으로는 CommandType.StoredProcedure 에 해당하는 작업을 수행합니다. 이들 메서들은 수행할 저장 프로시저 이름을 첫번째 매개변수로 사용합니다.

    1
    2
    3
    4
    5
    using FoxDbAccess dbAccess = FoxDbAccess.CreateDbAccess();
    FoxDbParameterCollection parameters = dbAccess.CreateParamCollection();
    parameters.AddWithValue("p_param1", ...);
    parameters.AddWithValue("p_param2", ...);    
    dbAccess.ExecuteSpNonQuery("my_proc_name", parameters);
    

    Note

    사용하는 Npgsql 버전에 따라 ExecuteSp- 메서드가 호출하는 대상이 달라집니다. Npgsql 7.x 버전부터는 ExecuteSp- 가 저장 프로시저를 호출하지만 그 이전 버전은 함수를 호출합니다. PostgreSQL 을 사용할 때 저장 프로시저보다 함수를 주로 사용한다면 다음 호출을 통해 Npgsql 7.x 이상 버전에서도 ExecuteSp- 메서드가 함수를 호출하도록 지정할 수 있습니다.

    AppContext.SetSwitch("Npgsql.EnableStoredProcedureCompatMode", true);
    
  • -Query- : Fox Query 를 수행합니다. Fox Query 는 .foxml 파일에서 SQL 문장, 데이터베이스 매개변수 정보를 포함하고 있습니다. ExecuteQuery- 메서드는 이러한 정보를 읽어 Command 객체를 구성하고 수행하며 그 결과를 반환합니다.

    Fox Query 는 수행할 쿼리를 찾기 위한 쿼리 ID를 매개변수로 사용하며 이 쿼리 ID에서 읽어야 할 .foxml 파일과 .foxml 파일 내의 쿼리를 알아냅니다.

    1
    2
    3
    using FoxDbAccess dbAccess = FoxDbAccess.CreateDbAccess();
    string queryId = "postgre.select_products";
    DataSet ds = dbAccess.ExecuteQueryDataSet(quryId, new { product_id = 20, product_name = "A%" });
    

    Fox Query 를 수행할 때 전달되는 DB 매개변수는 ExecuteSql-, ExecuteSp- 등의 다른 메서드들과는 차이점이 있습니다. Fox Query 의 DB 매개변수에 대해서는 Fox Query DB 매개변수 항목을 참고 하십시요.

  • -Command- : 매개변수로 주어진 Command 객체를 수행합니다. 이 메서드는 CreateCommand 메서드에 의해 생성된 Command 객체나 Fox DB Access 가 아닌 다른 API 를 통해 생성된 Command 객체를 매개변수로 사용합니다.

    1
    2
    3
    4
    using FoxDbAccess dbAccess = FoxDbAccess.CreateDbAccess();
    string queryId = "postgre.select_products";
    using IDbCommand command = dbAccess.CreateCommand(queryId, new { product_id = 20, product_name = "A%" });
    DataSet ds = dbAccess.ExecuteCommandDataSet(command);
    

수행 결과 접미사

두번째 접미사는 Execute- 시리즈 메서드가 반환하는 반환값을 나타냅니다. 이 접미사는 항상 수행할 커맨드 종류를 나타내는 접미사 뒤에만 사용됩니다.

  • -DataSet : 수행 결과를 DataSet 객체에 담아 반환합니다. 전형적으로 SELECT 문장(들)을 수행하고 그 결과셋(resultset)을 반환합니다. DataSet 객체에 포함된 DataTable 객체의 이름(DataTable.TableName 속성)은 Table 이며 FoxDbAccess 클래스의 DefaultTableName 속성으로 변경할 수 있습니다.

    using FoxDbAccess dbAccess = FoxDbAccess.CreateDbAccess();
    DataSet ds = dbAccess.ExecuteQueryDataSet("postgre.select_categories");
    
  • -List<T> : 수행 결과를 List<T> 객체로 반환합니다. 결과셋은 T 타입으로 매핑 됩니다. 대개 SELECT 류의 문장을 수행하고 그 결과를 담는 T 타입의 객체 목록을 획득하는데 사용됩니다. 예를 들어, 다음 예제는 SELECT 문장으로 읽은 데이터를 Product 객체에 매핑하여 List<Product> 컬렉션으로 반환합니다.

    1
    2
    3
    4
    5
    public class Product
    {
        public int Product_Id { get; set; }
        public string? Product_Name { get; set; }
    }
    
    1
    2
    3
    4
    5
    6
    using FoxDbAccess dbAccess = FoxDbAccess.CreateDbAccess();
    List<Product> products = dbAccess.ExecuteSqlList<Product>("SELECT * FROM products WHERE product_id < 3");
    foreach (Product product in products)
    {
        Console.WriteLine($"Product ID: {product.Product_Id}, Product Name: {product.Product_Name}");
    }
    
  • -NonQuery : 수행 결과를 반환하지 않습니다. INSERT, UPDATE, DELETE 류의 문장을 수행하거나 저장 프로시저를 호출할 때 사용합니다. INSERT/UPDATE/DELETE 류의 명령이 영향 받은 행(row) 개수를 정수값으로 반환합니다.

    1
    2
    3
    4
    5
    6
    7
    8
    using FoxDbAccess dbAccess = FoxDbAccess.CreateDbAccess();
    string query = "INSERT INTO my_demo_table VALUES(:id, :str, :int)";
    FoxDbParameterCollection parameters = dbAccess.CreateParamCollection();
    parameters.AddWithValue("id", 99);
    parameters.AddWithValue("str", "str99");
    parameters.AddWithValue("int", 99);
    int affectedRows = dbAccess.ExecuteSqlNonQuery(query, parameters);
    Console.WriteLine($"Inserted rows: {affectedRows}");
    

    Note

    PostgreSQL 은 Npgsql 의 버전에 따라 항상 -1 을 반환하는 경우도 있습니다.

  • -Scalar : 수행 결과를 스칼라(scalar) 값으로 반환합니다. 즉, SQL 문장 혹은 저장 프로시저가 반환한 결과셋에서 첫번째 행, 첫번째 열을 스칼라 값으로 반환합니다. 나머지 결과셋은 무시됩니다.

    1
    2
    3
    4
    5
    using FoxDbAccess dbAccess = FoxDbAccess.CreateDbAccess("Oracle");
    string query = "SELECT COUNT(*) FROM products";
    object? result = dbAccess.ExecuteSqlScalar(query);
    int count = Convert.ToInt32(result);
    Console.WriteLine($"Count: {count}");
    

    Note

    스칼라 값을 반환하는 경우 데이터베이스마다 반환되는 타입이 다를 수 있습니다. 예를 들어 SELECT COUNT(*) FROM ... 값은 PostgreSQL 은 long 타입(Int64)으로 반환되지만 Oracle 은 decimal 타입으로 반환됩니다. 따라서 단순한 형변환은 데이터베이스에 따라 오류를 유발할 수 있습니다. 안전한 변환은 Convert 클래스가 제공하는 ToXXX 메서드를 사용하는 것입니다.

  • -Reader : 수행 결과를 DataReader 객체로 반환합니다. 결과셋을 반환하는 SQL 문장 혹은 저장 프로시저를 수행하고 그 결과셋을 나타내는 DataReader 객체를 반환합니다.

    1
    2
    3
    4
    5
    6
    7
    using FoxDbAccess dbAccess = FoxDbAccess.CreateDbAccess();
    string query = "SELECT * FROM categories WHERE category_id <= 5";
    using IDataReader reader = dbAccess.ExecuteSpReader(query);
    while (reader.Read())
    {
        Console.WriteLine($"Category ID: {reader["category_id"]}, Category Name: {reader["category_name"]}");
    }
    

    FoxDbAccess 가 제공하는 ExecuteXXXReader 메서드들은 가장 전형적으로 DataReader 를 사용하는 패턴을 지원하고자자 CommandBehavior 설정으로 기본값(None)을 사용합니다. 다른 CommandBehavior 설정을 사용하여 DataReader를 사용하고자 한다면 FoxDbAccess 클래스의 CreateCommand 메서드를 호출하여 Command 객체를 생성하고 원하는 CommandBehavior 설정을 사용하여 ExecuteReader 메서드를 호출하십시요.

    using FoxDbAccess dbAccess = FoxDbAccess.CreateDbAccess();
    string query = "SELECT * FROM products WHERE product_id > 5";
    IDbCommand command = dbAccess.CreateCommand(query, CommandType.Text);
    dbAccess.Open();
    try
    {
        using IDataReader reader = command.ExecuteReader(CommandBehavior.SingleRow);
        while (reader.Read())
        {
            Console.WriteLine($"Product ID: {reader["product_id"]}, Product Name: {reader["product_name"]}");
        }
    }
    finally
    {
        dbAccess.Close();
    }
    

    Note

    Command.ExecuteReader 메서드는 FoxDbAccess 에 의해 제어되지 않으므로 데이터베이스 연결을 자동으로 열어주지 않습니다. 따라서 위 코드에서는 명시적으로 Open 메서드를 호출하고 try~finally 문장에 의해 Close 메서드를 호출합니다. FoxDbAccess 의 연결 관리에 대한 상세한 내용은 연결 관리 문서를 참고 하십시요.

  • - : 접미사가 없는 메서드는 DataSet 객체를 매개변수로 받고 SQL 문장 혹은 저장 프로시저를 수행한 결과셋으로 주어진 DataSet 객체를 채워넣습니다(fill). 여러개의 쿼리 결과를 하나의 DataSet 객체에 담거나 여러 데이터베이스의 쿼리 결과를 하나의 DataSet 객체에 담고자하는 경우에 유용합니다. 다음 예제는 PostgreSQL 과 Oracle 에 SELECT 문을 수행하고 하나의 DataSet에 채워 넣는 코드 입니다.

    using FoxDbAccess dbAccess1 = FoxDbAccess.CreateDbAccess("PostgreSQL");
    using FoxDbAccess dbAccess2 = FoxDbAccess.CreateDbAccess("Oracle");
    string query1 = "SELECT * FROM products WHERE product_id < 3";
    string query2 = "SELECT * FROM categories WHERE category_id < 3";
    DataSet ds = new();
    dbAccess1.ExecuteSql(query1, ["products"], ds);
    dbAccess2.ExecuteSql(query2, ["categories"], ds);
    foreach (DataRow row in ds.Tables["products"]!.Rows)
    {
        Console.WriteLine($"Product ID: {row["product_id"]}, Product Name: {row["product_name"]}");
    }
    foreach (DataRow row in ds.Tables["categories"]!.Rows)
    {
        Console.WriteLine($"Category ID: {row["category_id"]}, Category Name: {row["category_name"]}");
    }
    

    Note

    위 예제 코드에서 ExecuteSql 메서드 호출은 테이블 이름 매핑(mapping)을 사용합니다. 접미사가 없는 Execute- 메서드들은 내부적으로 DataAdapter.Fill 메서드를 호출하며 이 메서드는 테이블 이름 매핑이 사용되지 않는 경우 DataSet 의 첫번째 DataTable 에 결과를 채웁니다. 따라서 테이블 이름 매핑을 사용하지 않으면 두 ExecuteSql 메서드 호출은 하나의 DataTable 에 병합(merge)됩니다. 테이블 이름 매핑에 대한 상세한 내용은 이 문서에서 다시 상세히 언급됩니다.

    Note

    접미사가 없는 Execute- 메서드는 과거 .NET Framework 2.x 시절부터 Typed DataSet 지원을 위한 메서드이기도 합니다. Typed DataSet 은 최근에는 거의 사용하지 않는 데이터 컨테이너 입니다.

Execute- 메서드의 매개변수들

Execute- 시리즈 메서들에서 사용되는 여러 매개변수들에 대한 설명입니다. Execute- 메서드들은 매우 다양하기 때문에 사용하는 매개변수들도 매우 다양합니다. 여기서 설명되는 매개변수들은 Execute- 메서드들에 따라서 적용되는 여부가 달라질 수 있습니다.

수행 대상 매개변수

Exeucte 시리즈 메서드들의 첫번째 매개변수는 수행 대상을 나타내는 -Sql-, -Sp, -Query-, -Command- 접미사들과 연관이 있습니다.

  • ExecuteSql- 메서드들의 첫번째 매개변수는 수행할 SQL 문장 입니다.
  • ExecuteSp- 메서드들의 첫번째 매개변수는 수행할 저장 프로시저의 이름입니다.
  • ExecuteQuery- 메서드들의 첫번째 매개변수는 수행할 Fox Query 에 대한 쿼리 ID 입니다.
  • ExecuteCommand- 메서드들의 첫번째 매개변수는 수행할 Command 객체 입니다.

DB 매개변수

ExecuteQuery- 메서드들과 일부 ExecuteCommand- 메서드를 제외한 Execute- 시리즈 메서드들은 SQL 문장/저장 프로시저에 적용할 DB 매개변수를 사용할 수 있습니다. 예를 들어, FoxDbAccess 클래스는 SQL 문장을 수행하여 DataSet 객체를 반환하는 ExecuteSqlDataSet 메서드를 다음과 같이 정의합니다.

public DataSet ExecuteSqlDataSet(string query, IEnumerable<IDataParameter>? parameters = null)

SQL Server 를 위한 SqlParameter, Oracle 을 위한 OracleParameter, PostgreSQL 을 위한 NpgsqlParameter 등의 타입들들은 모두 IDataParameter 인터페이스를 구현하는 DbParameter 타입에서 파생되었습니다. 따라서 이들 타입에 대한 IEnumerable<IDataParameter> 를 지원하는 배열, 리스트(List<T>) 등의 타입을 모두 사용할 수 있습니다.

1
2
3
4
5
6
7
8
using FoxDbAccess dbAccess = FoxDbAccess.CreateDbAccess();
NpgsqlParameter[] parameters =
[
    new NpgsqlParameter("product_id", 20),
    new NpgsqlParameter("product_name", "A%")
];
string query = "SELECT * FROM products WHERE product_id <= :product_id AND product_name LIKE :product_name";
DataSet ds = dbAccess.ExecuteSqlDataSet(query, parameters);

배열이나 리스트를 사용하는 것보다 편리한 기능들을 갖는 FoxDbParamerCollection 객체를 사용하는 것이 더 권장됩니다. FoxDbParamerCollection 및 그 파생 클래스들(FoxSqlParameterCollection, FoxOracleParameterCollection, FoxNpgsqlParameterCollection 등)은 AddWithValue 메서드를 통해 컬렉션에 DB 매개변수를 손쉽게 추가할 수 있으며 null 값을 DBNull.Value 로 자동으로 변환하는 기능을 제공합니다. FoxDbParameterCollection 클래스는 IEnumerable<IDataParameter> 인터페이스를 구현하기 때문에 Execute- 시리즈 메서드에 사용할 수 있습니다. 더욱이 FoxDbParameterCollection 타입은 특정 데이터베이스에 의존적이지 않은 추상 클래스이므로 데이터베이스에 의존성이 없는 FoxDbAccess 클래스와 사용하기 적합합니다.

1
2
3
4
5
6
using FoxDbAccess dbAccess = FoxDbAccess.CreateDbAccess();
FoxDbParameterCollection parameters = dbAccess.CreateParamCollection();
parameters.AddWithValue("product_id", DbType.Int16, 20);
parameters.AddWithValue("product_name", DbType.String, "A%");
string query = "SELECT * FROM products WHERE product_id <= :product_id AND product_name LIKE :product_name";
DataSet ds = dbAccess.ExecuteSqlDataSet(query, parameters);

ExecuteCommand- 메서드들 중 일부는 IEnumerable<IDataParameter> 매개변수를 사용하지 않습니다. ExecuteCommand- 메서드는 CreateCommand 메서드나 Fox DB Access 를 사용하지 않고 다른 방법으로 생성된 Command 객체를 수행하는 메서드 입니다. 이렇게 생성된 Command 객체는 데이터베이스 매개변수에 대한 설정이 이미 완료되기 때문에 ExecuteCommand- 메서드에서 IEnumerable<IDataParameter> 매개변수가 포함되지 않는 것입니다.

1
2
3
4
5
6
7
using FoxDbAccess dbAccess = FoxDbAccess.CreateDbAccess();
string query = "SELECT * FROM products WHERE product_id <= :product_id AND product_name LIKE :product_name";
FoxDbParameterCollection parameters = dbAccess.CreateParamCollection();
parameters.AddWithValue("product_id", DbType.Int16, 20);
parameters.AddWithValue("product_name", DbType.String, "A%");
using IDbCommand command = dbAccess.CreateCommand(query, CommandType.Text, parameters);
DataSet ds = dbAccess.ExecuteCommandDataSet(command);

Note

위 코드에서 CreateCommand 메서드 호출과 ExecuteCommand 메서드 호출을 한번에 호출하는 단축(short-cut) 메서드에서는 IEnumerable<IDataParameter> 매개변수가 포함될 수도 있습니다. 이 경우 첫번째 매개변수가 Command 객체가 아닌 CommandText 문자열(SQL 문장 혹은 저장 프로시저 이름)이 됩니다.

1
2
3
//IDbCommand command = dbAccess.CreateCommand(query, CommandType.Text, parameters);
//DataSet ds = dbAccess.ExecuteCommandDataSet(command);
DataSet ds = dbAccess.ExecuteCommandDataSet(query, CommandType.Text, parameters);

Fox Query 의 DB 매개변수

Fox Query 를 수행하는 메서드의 DB 매개변수는 작동 방식이 다릅니다. Fox Query 는 .foxml 파일에 SQL 문장 뿐만 아니라 매개변수 정보들도 기록해 두기 때문에 ExecuteQuery- 메서드들이 수행될 때 DB 매개변수들도 이 정보를 사용하여 자동으로 생성됩니다.

예를 들어, 다음과 같은 Fox Query 파일(.foxml) 의 <statement> 태그가 있을 때 <parameters> 태그는 Command 객체의 Parameters 컬렉션에 DB 매개변수들을 설정합니다. 이 예제의 경우 product_id, product_name 이라는 이름을 가진 DB 매개변수가 생성됩니다.

<statement id="select_products">
  <text>
    <![CDATA[
      SELECT * FROM products WHERE product_id <= #product_id# AND product_name LIKE #product_name#
    ]]>
  </text>
  <parameters>
    <parameter name="product_id" dbType="Integer" />
    <parameter name="product_name" dbType="String" />
  </parameters>
</statement>

Information

ExecuteQueryDataSet 메서드가 수행하는 과정을 FoxDbAccess 가 제공하는 Fox Query 관련 API 들로 풀어서 다시 작성해보면 다음과 같습니다.

using FoxDbAccess dbAccess = FoxDbAccess.CreateDbAccess();
Dictionary<string, object?> parameters = new()
{
    { "product_id", 20 },
    { "product_name", "A%" }
};
FoxQuery foxquery = dbAccess.GetQuery("postgre.select_products");
using IDbCommand command = dbAccess.CreateCommand(foxquery, parameters);
foreach(IDataParameter p in command.Parameters)
{
    Console.WriteLine($"Parameters[\"{p.ParameterName}\"].Value = {p.Value}");
}
DataSet ds = dbAccess.ExecuteCommandDataSet(command);
// result output:
// Parameters["product_id"].Value = 20
// Parameters["product_name"].Value = A%    

위 코드를 통해 Command 객체를 생성할 때 DB 매개변수가 이미 구성되어 있다는 것을 알 수 있습니다.

DB 매개변수가 이미 설정되어 있으므로 ExecuteQuery- 메서드를 수행하기 위해서는 DB 매개변수의 값(들)만을 전달하면 됩니다. 따라서 ExecuteQuery- 메서드에서는 DB 매개변수가 아닌 DB 매개변수 값(들)을 전달해야 합니다.

public DataSet ExecuteQueryDataSet(string queryId, object? parameterObject = null);

ExecuteQuery- 메서드의 parameterObject 매개변수에 사용할 수 있는 객체는 다음과 같습니다.

  • IDictionary 객체

    DB 매개변수 컬렉션에서 매개변수 이름에 대응되는 IDictionary 키/값을 찾아 DB 매개변수 값으로 사용합니다. Fox Biz/Data Service Web API 에서 사용되는 매개변수 컬렉션이 IDictionary 를 사용하므로 이 때 많이 사용됩니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    [FoxBizMethod]
    public DataSet MyBizMethod(IDictionary<string, object?> parameters)
    {
        // 보안/안정성 등을 위한 매개변수 검증 (생략)
    
        FoxDbAccess dbAccess = FoxDbAccess.CreateDbAccess();
        DataSet ds = dbAccess.ExecuteQueryDataSet("my_foxml_file.some_id", parameters);
        return ds;
    }
    
  • DataRow 객체

    DB 매개변수 컬렉션에서 매개변수 이름에 대응되는 DataRow 컬럼을 찾아 그 값을 설정합니다. DataTable 의 변경 사항을 일괄적으로 추가/수정/삭제 할 때 많이 사용됩니다.

    foreach(DataRow row in ds.Tables[0].Rows)
    {
        if (row.RowState == RowState.Added)
        {
            dbAccess.ExecuteQueryNonQuery("my_foxml.insert", row);
        }
        else if (row.RowState == RowState.Modified)
        {
            dbAccess.ExecuteQueryNonQuery("my_foxml.update", row);
        }
        // ... 생략...
    }
    
  • 일반 닷넷 객체

    DB 매개변수 컬렉션에서 매개변수 이름에 대응되는 객체의 속성/필드를 찾아 그 값을 설정합니다. 엔티티 기반 앱에서 사용하거나 익명 타입(anonnymous type)을 사용하여 간단한 구현에 사용합니다.

    1
    2
    3
    DataSet ds = dbAccess.ExecuteQueryDataSet(
        "postgre.select_products", 
        new { product_id = 20, product_name = "A%" });
    

테이블 이름 매핑(mapping)

수행한 SQL 문장 혹은 저장 프로시저가 여러 테이블을 반환하는 경우 DataSet 객체는 여러 DataTable 객체를 포함하게 됩니다. 여러 DataTable의 이름은 기본적으로 DefaultTableName 속성값을 사용하고 뒤에 숫자가 붙는 형태로 적용됩니다. DefaultTableName 속성을 변경하지 않았다면 DataTable 의 이름들은 Table, Table1, Table2 등이 됩니다.

1
2
3
4
5
6
7
8
using FoxDbAccess dbAccess = FoxDbAccess.CreateDbAccess();
string query= "SELECT * FROM products WHERE product_id < 3; SELECT * FROM categories WHERE category_id < 3";
DataSet ds1 = dbAccess.ExecuteSqlDataSet(query);
Console.WriteLine($"Table[0].TableName={ds1.Tables[0].TableName}");
Console.WriteLine($"Table[1].TableName={ds1.Tables[1].TableName}");
// result output:
// Table[0].TableName=Table
// Table[1].TableName=Table1

DefaultTableName 속성값을 ResultSet 으로 변경했다면 DataSet에 포함된 DataTable의 이름들은 ResultSet, ResultSet1, ResultSet2 가 됩니다.

1
2
3
4
5
6
7
8
9
using FoxDbAccess dbAccess = FoxDbAccess.CreateDbAccess();
string query= "SELECT * FROM products WHERE product_id < 3; SELECT * FROM categories WHERE category_id < 3";
dbAccess.DefaultTableName = "ResultSet";
DataSet ds1 = dbAccess.ExecuteSqlDataSet(query);
Console.WriteLine($"Table[0].TableName={ds1.Tables[0].TableName}");
Console.WriteLine($"Table[1].TableName={ds1.Tables[1].TableName}");
// result output:
// Table[0].TableName=ResultSet
// Table[1].TableName=ResultSet1

-DataSet 접미사를 사용하는 Execute- 메서드들은 앞서 언급한 방식이외에도 DataTable 의 이름을 임의로 지정가능한 매핑 정보를 매개변수로 사용할 수 있습니다.

public DataSet ExecuteSqlDataSet(string query, string[] mappingNames, IEnumerable<IDataParameter> parameters);

테이블 이름 매핑 정보가 주어지면 DataTable 의 이름은 테이블 이름 매핑 정보에 의해 지정됩니다.

using FoxDbAccess dbAccess = FoxDbAccess.CreateDbAccess();
string query = "SELECT * FROM products WHERE product_id < :product_id; SELECT * FROM categories WHERE category_id < :category_id";
string[] mappingNames = ["Products", "Categories"];

FoxDbParameterCollection parameters = dbAccess.CreateParamCollection();
parameters.AddWithValue("product_id", DbType.Int16, 3);
parameters.AddWithValue("category_id", DbType.Int16, 3);

DataSet ds1 = dbAccess.ExecuteSqlDataSet(query, mappingNames, parameters);
Console.WriteLine($"Table[0].TableName={ds1.Tables[0].TableName}");
Console.WriteLine($"Table[1].TableName={ds1.Tables[1].TableName}");
// result output:
// Table[0].TableName=Products
// Table[1].TableName=Categories

외부 커맨드 수행

가끔씩 FoxDbAccess 클래스를 통해 Execute- 메서드들을 수행하기 어렵거나 FoxDbAccess 가 제공하는 CreateCommand 메서드를 사용하기 어려울 때가 있을 수 있습니다. 예를 들어 CommandBuilder 클래스를 통해 INSERT/UPDATE/DELETE 문장을 포함하는 Command 객체를 사용하고자 하는 상황입니다. 다음 예제는 CommandBuilder 클래스를 통해 INSERT SQL 문장을 포함하는 커맨드 객체를 생성하고 수행하는 예를 보여 줍니다.

1
2
3
4
5
6
7
8
9
using FoxDbAccess dbAccess = FoxDbAccess.CreateDbAccess();
IDbDataAdapter adapter = dbAccess.CreateDataAdapter();
adapter.SelectCommand = dbAccess.CreateCommand("SELECT * FROM my_demo_table", CommandType.Text);
NpgsqlCommandBuilder builder = new((NpgsqlDataAdapter)adapter);
NpgsqlCommand command = builder.GetInsertCommand();
command.Parameters["p1"].Value = 99;
command.Parameters["p2"].Value = "str99";
command.Parameters["p3"].Value = 99;
dbAccess.ExecuteCommandNonQuery(command);

Fox DB Access 가 아닌 외부 API 를 통해 생성된 Command 객체를 FoxDbAccess 클래스를 통해 수행할 때 얻을 수 있는 장점은 FoxDbAccess 객체가 제공하는 연결 관리 기능, 트랜잭션 처리 기능의 적용을 받을 수 있으며 해당 Command 객체에 대한 DB 프로파일 정보도 같이 얻을 수 있기 때문입니다.

Summary

Fox DB Access 는 SQL 문장을 수행하거나 저장 프로시저를 편리하게 호출하기 위해 매우 다양한 Execute- 메서드들을 제공합니다. SQL 문장을 수행하기 위한 ExecuteSql- 메서드들, 저장 프로시저 호출을 위한 ExecuteSp- 메서드들을 비롯하여 .foxml 파일에서 Fox Query 를 읽어 들어 수행하는 ExecuteQuery- 메서드들과 다양한 방법을 통해 생성된 Command 객체를 수행하는 ExecuteCommand- 메서드들도 제공됩니다. 이들 메서드들은 쿼리 수행 결과로서 DataSet 객체, 스칼라 값, DataReader 객체를 반환하거나 쿼리 수행 결과를 무시할 수도 있습니다.

Execute- 메서드들은 수행하고자 하는 대상(SQL 문장, 저장 프로시저, Fox Query 등)과 수행 결과(DataSet, DataReader 등)에 따라 매개변수, 작동 방식에서 약간의 차이점이 있지만 이 문서에서 설명한 내용을 숙지하면 사용하는데 어려움은 없을 것입니다. 이들 Execute- 메서드들을 통해 개발자는 전통적인 데이터 액세스 방법보다 훨씬 더 적은 노력과 시간으로 보다 데이터 액세스를 수행할 수 있습니다.