FoxQuery 수행¶
Foxml 파일에 기록된 FoxQuery 를 수행하는 방법에 대해서 설명합니다. Fox DB Access 에서 데이터베이스를 액세스하는 기본적인 방법들은 FoxDbAccess 커맨드 수행에서 설명하였으므로 해당 문서를 먼저 참조하십시요.
이 문서와 관련된 예제 코드는 다음 예제를 참조 하십시요.
ExecuteQuery-
메서드¶
FoxQuery 를 수행하기 위해서는 ExecuteQuery-
메서드를 호출하면 됩니다. ExecuteQuey-
메서드는 내부적으로 FoxQueryMapper
객체를 통해 호출 대상 FoxQuery 정보를 획득하고 이 정보를 사용하여 Command
객체를 생성합니다. 그리고 최종적으로 생성한 Command
객체를 수행하고 그 결과를 보여 줍니다. 다음 코드는 이와 같은 과정을 보여줍니다.
ExecuteQuery-
메서드를 사용하면 다음과 같이 간단하게 호출이 가능합니다.
ExecuteQuery-
메서드들은 쿼리 수행 결과를 DataSet
객체(ExecuteQueryDataSet
메서드), List<T>
객체(ExecuteQueryList<T>
메서드), DataReader
객체(ExecuteQueryReader
메서드) 등으로 반환할 수 있습니다. 쿼리 수행 결과에 따른 ExecuteQuery-
메서드들에 대해서는 수행 결과 접미사를 참조 하십시요.
FoxQuery Id ¶
ExecuteQuery-
메서드 호출에서 FoxQuery 를 수행시키기 위해서는 수행 대상이 되는 FoxQuery Id 를 사용해야 합니다. FoxQuery Id 는 두 부분으로 나누어 지며 앞 부분은 FoxQuery 를 찾을 .foxml
파일을 나타내며 뒷 부분은 .foxml
파일 내에서 FoxQuery 를 찾는데 사용됩니다.
FoxQuery Id 에 :
문자가 포함되어 있으면 :
문자를 기준으로 앞 부분은 .foxml
파일을, 뒷 부분은 .foxml
파일 내의 <statement>
혹은 <procedure>
태그의 id
속성을 나타냅니다. 예를 들어 FoxQuery Id 가 northwind:get_product
이라면 northwind.foxml
파일 내에서 id
가 get_product
인 쿼리를 수행합니다.
Note
FoxQueryMapper 는 구성 설정에 따라서 여러 디렉터리에서 .foxml
파일들을 검색합니다. 이들 .foxml
파일들을 구분하는 유일한 기준은 파일 이름이며 디렉터리 위치는 무시합니다. 예를 들어 ./dir1/myquery.foxml
파일과 ./dir2/myquery.foxml
파일이 존재하는 경우 두 파일은 같은 것으로 간주되어 FoxInvalidQueryException
예외가 발생합니다.
:
문자에 의해 구분되는 FoxQuery Id 는 .foxml
파일 이름에 아무런 제약이 없습니다. Fox Query 는 FoxQuery Id 에 :
문자 없이 .
문자로 구분하는 것도 호환됩니다. .
문자가 사용된 경우, 첫번째 .
문자를 기준으로 앞 부분은 .foxml
파일을 나타내며 뒷 부분은 .foxml
파일 내에서 쿼리 Id 를 나타냅니다. 예를 들어 northwind.get_product
가 주어지면 northwind.foxml
파일에서 id
속성이 get_product
인 쿼리를 찾습니다.
Information
:
문자 구분은 NeoDEEX 5.x 부터 사용되며 하위 호환성을 위해 .
문자 구분도 지원합니다. .foxml
파일을 구분하는데 디렉터리 이름이 사용되지 않기 때문에 .foxml
파일 이름에 구분자를 넣어야 합니다. .
문자로 구분되는 FoxQuery Id 는 common.query.foxml
과 같이 .foxml
파일에 .
문자를 구분자로 사용할 수 없게 만듭니다. 이런 이유에서 :
문자로 구분하는 FoxQuery Id 가 새롭게 추가되었습니다.
DB 매개변수 인자(argument)¶
Parameter vs Argument
Parameter 와 Argument 는 잘 구분이 되지 않는 용어 입니다. 일반적으로 메서드 정의에서 나타나는 변수를 형식 매개변수(formal parameter), 그냥 짧게 줄여 매개변수(parameter) 라고 하며 메서드 호출에 사용된 매개변수 값을 실질 매개변수(actual parameter) 혹은 인자(argument) 라고 부릅니다. 예를 들어 다음과 같은 메서드 정의와 호출에서 foo
메서드 정의에 나타난 x
는 매개변수이며 foo(5)
호출에 사용된 5
는 인자 입니다.
많은 경우 형식 매개변수와 실질 매개변수를 구분하지 않고 그냥 매개변수라고 통칭하는 경우가 많습니다. 하지만 Fox Query 에서는 형식 매개변수는 .foxml
에서 <parameter>
태그를 통해 정의하고 실질 매개변수는 ExecuteQuery-
메서드를 호출할 때 사용하는 값을 말합니다. 특히, Fox Query 의 매크로에서는 매개변수와 인자를 구분하여 사용해야 합니다.
FoxQuery 를 수행할 때 매개변수 인자(actual parameter; argument)로 사용 가능한 객체는 IDictionary
, DataRow
, Object
객체 입니다.
IDictionary
매개변수 인자¶
IDictionary
객체라 함은 이 인터페이스를 구현하는 Hashtable
객체나 IDictioary
인터페이스에서 파생된 IDicionary<K,V>
인터페이스를 구현하는 Dictionary<K, V>
객체 등을 말합니다. 일반적으로 IDictionary
인터페이스를 사용하는 경우는 매우 드물며 IDictionary<K,V>
인터페이스를 사용하는 경우가 일반적입니다. 즉, Dictionary<K,V>
객체나 IDictionary<string, object?>
인터페이스를 지원하는 FoxParameterCollection
객체도 매개변수 인자로 사용이 가능합니다.
FoxParameterCollection
클래스
FoxParameterCollection
클래스는 NeoDEEX 에서 일반적으로 정보를 교환하는데 사용되는 키/값 스타일 컬렉션 입니다. FoxParameterCollection
객체는 Fox Biz/Data Service 에서 서비스를 호출할 때 매개변수로 사용되기도 하며 WinForm 환경에서 두 Form
이 정보를 교환할 때에도 사용됩니다. 이 컬렉션은 IDictionary<string, object?>
인터페이스를 구현할 뿐만 아니라 고성능 JSON 직렬화, null
값을 DBNull.Value
로 변환 기능 등 개발에 편리한 기능을 제공합니다.
IDictionary<string, object?>
타입은 일반적으로 닷넷 기반 앱에서 클라이언트/서버 환경에서 서버를 호출할 때 매개변수를 전달하는데 사용하는 DTO(Data Transfer Object) 타입이며 클라이언트로부터 전송된 JSON 객체를 역직렬화(deserialization) 하기 쉬운 타입이기도 합니다. 이런 이유에서 FoxQuery 역시 매개변수 인자로 IDictionary
객체를 지원하는 것입니다.
다음은 Fox Biz Service 의 비즈 메서드의 구현 예를 보여줍니다. FoxBizRequest
클래스는 Fox Biz Service 를 호출할 때 사용하는 DTO(Data Transfer Object) 객체이며 Parameters
속성은 IDictionary<string, object?>
인터페이스를 구현하는 컬렉션 입니다.
DataRow
매개변수 인자¶
DataRow
객체는 DataTable
에서 테이블의 열을 나타내는 객체 입니다. DataSet
은 엔티티에 비해 무겁고 성능도 상대적으로 낮으며 실수 가능성이 높은 데이터 컨테이너입니다. 하지만 DataSet
은 여러 개발 환경에서 높은 개발 생산성과 편리함을 제공하기 때문에 NeoDEEX 는 DataSet
에 대한 지원을 많이 포함합니다.
FoxQuery 역시 매개변수 인자로서 DataRow
를 지원합니다. DataSet
이 지원하는 데이터 추가/수정/삭제 기능에 의해 변경된 데이터 열들을 손쉽게 데이터베이스에 저장할 수 있습니다. 다음 예제 코드는 데이터베이스에서 읽어온 DataTable
을 변경하고 그 변경 사항을 다시 저장하는 예를 보여줍니다.
데이터베이스에서 조회된 데이터가 DataSet
에 기록되면 DataRow
는 변경 사항을 추적합니다. DataRow
는 RowState
속성을 통해 DataRow
가 추가/수정/삭제되었는지 파악이 가능합니다. 여러 데스크톱 앱에서 사용되는 많은 UI 컴포넌트 들은 DataSet
을 지원하며 특히 데이터 그리드와 같은 UI 컴포넌트들을 데이터 바인딩된 DataRow
들에 대한 추가/수정/삭제를 허용하며 이러한 변경 사항들은 그대로 추적됩니다. 데스크톱 앱은 변경된 DataRow
들을 GetChanges
메서드를 통해 추출해 내고 이들을 사용하여 데이터베이스 변경 사항을 저장할 수 있습니다.
Information
물론 위 예제 코드와 같이 데스크톱 앱이 직접 데이터베이스에 변경된 DataRow
를 저장하지 않습니다. 변경된 DataRow
를 포함하는 DataTable
혹은 DataSet
을 서버로 전송하여 서버 측에서 저장을 수행하게 됩니다. NeoDEEX 는 이러한 작업을 위해 DataSet
, DataTable
을 직렬화할 때 RowState
정보를 포함하도록 하며 Fox Data Service 는 SaveDataTable
API 도 지원합니다.
위 코드가 작동하기 위해서는 추가/수정/삭제를 수행하는 FoxQuery 역시 정의되어야 합니다. 다음 FoxQuery 는 추가/수정/삭제를 수행하는 <statement>
태그들을 보여줍니다. 이들 <statement>
들은 DB 매개변수의 이름을 DataRow
의 컬럼 이름과 동일하게 지정하고 있습니다. 만약 DB 매개변수 이름과 DataRow
의 컬럼 이름이 같지 않다면 property
속성을 사용해야 합니다.
Note
위 <statement>
태그 중에서 주의깊게 살펴볼 부분은 삭제를 수행하는 delete_demo
쿼리 입니다. 다른 <statement>
태그들을 <parameter>
태그를 사용하지 않고 자동으로 추가되는 기능을 활용하고 있습니다. 하지만 delete_demo
쿼리는 명시적으로 <parameter>
태그를 사용하고 있습니다. 그 이유는 삭제된(Deleted
) DataRow
의 데이터는 기본적으로 읽을 수 없기 때문입니다. 따라서 삭제된 값이 아닌 원본 값을 읽도록 rowVersion
속성을 Original
로 지정하고 있습니다.
Object
매개변수 인자¶
IDictionary
혹은 DataRow
가 아닌 경우 ExecuteQuery-
메서드는 매개변수 인자를 일반 Object
로 간주합니다. FoxQuery 를 수행하는데 필요한 DB 매개변수 값은 주어진 Object
매개변수 인자의 속성이나 필드에서 리플렉션(refletion)을 통해 추출됩니다.
다음 코드는 익명 타입(anonymous type)을 사용하여 매개변수 객체를 생성하고 이를 사용하여 FoxQuery 를 수행하는 예를 보여 줍니다.
Note
매개변수 인자 객체의 속성 이름과 FoxQuery 의 DB 매개변수 이름은 대소문자를 구분하지 않습니다. 다음 FoxQuery 정의는 DB 매개변수 이름이 모두 소문자이지만 대소문자를 섞어쓴 위 매개변수 인자 객체와 잘 작동합니다.
Object
매개변수 인자와 ExecuteQueryList<T>
메서드는 ORM 과 비슷한 코딩 기법을 수행할 수 있도록 해줍니다. 예를 들어 테이블에 매핑되는 Product
객체를 다음과 같이 정의하면,
다음과 같이 매개변수 인자를 구성하고 쿼리 수행 결과를 Proudct
객체의 목록(List<Product>
)으로 받아올 수 있습니다.
Object
매개변수 인자는 직관적이며 ExecuteQueryList<T>
메서드 호출과 매우 잘 어울리며 ORM 과 유사한 작업을 수행할 수 있지만 리플렉션을 사용하기 때문에 성능상 다른 매개변수 인자에 비해 불리합니다. 또한 Obejct
매개변수 인자와 ExecuteQueryList<T>
메서드는 Entity Framework 와 같은 ORM 프레임워크와는 비교할 수 없습니다. Entity Framwork 는 엔티디를 다루는 코드로부터 SQL 문장을 생성하고 수행하지만 Fox Query 는 SQL 문장을 수행하고 그 결과를 받아오기 위해 엔티티 객체를 사용할 뿐입니다.
Summary¶
FoxQuery를 수행하기 위해서는 ExecuteQuery-
메서드들을 호출해야 합니다. 이들 메서드들에는 수행 대상이 되는 FoxQuery 를 나타내기 위해 :
문자 혹은 .
문자로 구분되는 FoxQuery Id 를 사용해야 합니다. FoxQuery 에 정의된 DB 매개변수에 대한 인자 값으로 IDictionary
, DataRow
, Object
객체를 사용할 수 있으며 각각의 장단점이 존재합니다. FoxQuery는 SQL 문장을 직접 수행하며, Entity Framework와 같은 ORM 프레임워크와는 구별됩니다.