Jump to content
과거의 기술자료(읽기 전용): https://tech.devgear.co.kr ×
과거의 기술자료(읽기 전용): https://tech.devgear.co.kr

날짜 필드에 빈 값을 허용하는 방법


Recommended Posts

Dr. Holger Flick가 진행하는 "How it works with Holger" 비디오 시리즈는 개발자가 당면하는 흔하고 반복되는 문제들 그리고 개발자라면 반복해서 사용하게 될 빌딩 블록을 선정하고 선정된 각 문제마다 근본적이고 단순한 지식, 직접 해볼 수 있는 해법, 소스 코드, 설명을 제공하는 짧은 비디오들이 들어있는 시리즈이다. TMS가 스폰서이지만, TMS에 종속적이기보다는 델파이 개발자가 알고 있으면 좋을 개발 지식을 주로 다룬다.

이 글은 이 비디오 시리즈 중에서 "날짜 필드에 빈 값을 허용하는 방법 (How to allow dates to be empty?)""에 대한 비디오의 주요 내용을 요약/번역했습니다. (원문 작성: 2022년 11월, 최종 번역: 2022년 11월)

아래 번역은 요약입니다. 보다 자세하게 보다 생생하게 알고 싶다면, 위에 있는 12분 남짓한 원본 영상(영어)을 보기 바랍니다.

여러분은 델파이 애플리케이션에서 날짜 필드에서 '빈값(empty value)'을 받아야 할 때 어떻게 하나?

데이터베이스에서 Null, 델파이에서 Nil은 해당 필드에는 어떠한 값도 할당된 것이 없다는 의미이다.
데이터베이스에서는 간단하다. 해당 데이터 필드(컬럼)를 Null 허용 필드로 지정하고 해당 레코드에서 그 필드에 Null을 넣으면 된다.
하지만, 델파이에서는 그렇지 않다. 델파이의 TDate 타입은 포인터(pointer)가 아니기 때문에 (실제로 Double 타입이다) Date 타입의 값에 Nil을 할당할 수 없다.

데이터베이스 레코드 중에서 날짜 필드의 값이 Null인 레코드를 델파이에서 사용하려면 어떻게 할까?

어떤 개발자들은 이 레코드에 Boolean 필드를 더 추가하여 그 Boolean 필드가 Yes 이면 날짜 필드에서 값을 읽어오고, No 이면 그 날짜 필드를 읽지 않고 뭔가 다른 진행을 한다. 하지만, UI에서는 이런 방식이 크게 도움되지 않는다.

이 문제에 대해 설명하기에 앞서 Nullable에 대해서 먼저 설명하고자 한다.

2022년 현재 아직 델파이는 언어 차원에서 Nullable를 지원하고 있지는 않다. 문제가 될 것 같지만, 사실 그다지 문제되지 않는다. 델파이 커뮤니티에서 훌륭한 친구들이 우리를 위해 이미 구현해 놓았기 때문이다. 우리는 델파이에서도 Date 타입에서 이렇게 이미 구현된 Nullable을 사용하면 된다.

우리가 사용할 예시를 보자.

'프로젝트 완료' Checkbox를 선택하면 완료일자 DateTimePicker에서 날짜를 선택할 수 있고, '완료일 보기' Button을 클릭하면 프로젝트 완료일이 메시지 창에 표현되는 간단한 화면이다. 완료 Checkbox가 선택되지 않은 상태에서는 완료일을 지정할 수 없고, 완료일 보기를 클릭하면 '프로젝트가 완료되지 않았습니다'가 표시된다. 

사용자가 '완료일 보기' Button을 클릭했을 때, 실제 완료일자와 아직 완료되지 않았다는 메시지 중 무엇을 보여줄 것인지를 어떻게 판단할까?

'프로젝트 완료' Checkbox가 체크되어 있는지 아닌지를  보고 판단할 수 있을 것이다.

하지만, 나는 그저 '완료일자'이라는 UI요소만으로 처리할 수 있기를 바란다. 

하지만, 델파이에서 TDate 타입은 실제로 TDateTime 타입이고, TDateTime 타입은 Double 타입이다. 우리가 Nil을 할당하려면 포인터 타입이어야 하는데, Double은 포인터가 아니기 때문에 Nil을 할당할 수 없다.

이럴 때. 델파이 개발자들은 '특정 날짜 값'을 미리 약속해놓는 방법을 많이 사용한다.

실제로 지정될 가능성이 거의 없는 날짜를 미리 지정해 두고, TDate에 그 날짜 값이 들어 있으면, 실제로는 할당된 값이 없는 것으로 판단한다. 빈 값으로 간주할 '특정 날짜 값'은 주로 상수로 만들어 두고, 날짜 필드에 들어 있는 값을 이 상수와 비교하는 로직을 사용하여 판단한다.

이 방식은 위와 같이 읽을 때 추가 코드가 필요하다. 게다가 데이터베이스 안에 그 값을 써 넣어야 할 때에는 여기에 더하여 특정 날짜인 값을 다시 Null로 바꿔서 넣는 코드가 더 필요하다.

아래와 같이 Nullable을 사용하면 훨씬 더 쉽게 처리할 수 있다.

property FinishedDate: Nullable<TDate> read GetFinishedDate;

Nullable을 사용하기 위해 나는 델파이에 Spring4Delphi를 추가했다. Spring4Delphi 외에도 델파이 개발자가 Nullable을 사용할 수 있는 방법은 많다. TMS의 Biz Core 라이브러리(TMS Aurelius 또는 XData에서 사용되고 있다)를 사용할 수도 있다. Aurelius는 오브젝트와 관계형 데이터를 맵핑하는 프레임워크이므로 Null 값을 클래스 또는 오브젝트에 맵핑해야 할 테니 이런 구현이 필요한 건 당연하다). 그 외에도 Paolo Rossi가 델파이로 구현한 JOSE 프레임워크에도 Nullable<T>가 구현되어 있다.

이 예시에서 내가 Spring4Delphi를 선택한 이유는 너무나 간단히 설치할 수 있고, 많은 델파이 버전에서 사용할 수 있기 때문이다.

Spring4Delphi의 Downloads를 가서, 최신 리포지토리를 다운로드하고, 다운로드된 폴더에서 Build.exe파일을 실행하면 된다. 해당 컴퓨터에 설치된 델파이를 탐지되고 우리가 원하는 델파이 버전과 컴파일러 선택하고 버튼을 클릭하면 Spring4D가 설치된다.

Spring4Delphi가 설치되고 나면, 사용하고 싶은 곳의 uses 절에 Spring을 추가하고 사용하면 된다.
uses에 Spring을 추가하고, Spring에 커서를 두고 Ctrl+클릭을 하여 Spring 소스를 보면 Nullable이 Record 타입으로 구현되어 있음을 그리고 Nullable<T>가 제네릭 레코드로 구현된 코드를 볼 수 있다. (자세한 코드는 동영상을 보거나, Spring4D를 설치해 볼 것 - 옮긴이)

사용할 때에는 빈 값을 허용하고 싶은 타입에서 Nullable을 사용하기만 하면 된다 (예: Nullable<TDate>)

예를 들어,

var LDate: Nullable<TDate>;  인 경우, LDate에 날짜를 넣을 수 있을 뿐만 아니라 (예: LDate := Now;), Nullable에 구현된 헬퍼를 사용할 수 도 있다. 헬퍼에는 가장 중요한 HasValue 프로퍼티, Value 프로퍼티 뿐만 아니라 GetValueOrDefault, ToString 함수 등이 들어있어서 매우 편하다.

1 Nullable Helper.png

이 LDate에 빈 값을 넣으려면 LDate := nil; 을 적어 주면 된다.

만약 LDate가 Nullable<TDate>가 아니라 그냥 TDate 였다면 이 코드는 컴파일 오류가 나고, 타입 불일치: TDate'와 'Pointer'라는 오류 메시지가 표시된다.

화면으로 돌아가서, DateTimePicker VCL 컨트롤은 Nullable을 허용하지 않으므로, 여기에 빈 값을 넣을 수 없다. (TMS 등 써드-파티에서 제공하는 컨트롤 중에는 이 화면에서 있는 것과 같이 조건에 따라 날짜 입력을 허용하는 날짜 선택 컨트롤이 있는데, 지금 설명하는 코드가 그 안에 구현되어 있기 때문이다)

이 두 프로퍼티를 만들어서 활용한다. 

property IsFinished: Booleaan read GetIsFinished write SetIsFinished;
property FinishedDate: Nullable<TDate> read GetFinishedDate;

IsFinished라는 프로퍼티는 사용자가 화면에서 '프로젝트 완료'를 선택했는지 여부를 반영한다.
FinishedDate 프로퍼티에서 사용하는 read 함수는 아래와 같다.

// FinishedDate 프로퍼티를 읽으면, nil 또는 완료 일자가 반환된다
function TFrmMain.GetFinishedDate: Nullable<TDate>;
begin
  Result := nil; //일단 빈 값을 기본값으로 
  if IsFinished then //프로젝트가 끝났으면
  begin
    Result := dtFinished.Date; //날짜 선택기에 선택된 날짜
  end;
end;

사용자가 완료일 보기 버튼을 클릭하면 다음 코드가 실행된다.

// 화면에서 체크박스를 확인하지 않고도 Nullable인 FinishedDate 필드만 가지고도 로직을 수행할 수 있다.
procedure TFrmMain.ShowDate;
begin
  if FinishedDate.HasValue then // Nullable의 헬퍼 함수인 HasValue를 사용한다.
  begin
    ShowMessage( FinishedDate.ToString );
  end
  else
  begin
    ShowMessage( '프로젝트가 완료되지 않았습니다' );
  end;
end;

(원본 비디오에서는 보다 자세히 코드를 설명합니다 - 옮긴이)

요컨데, Nullable<TDate>는 빈 값을 받을 수 있는 날짜 필드를 사용할 수 있게 해준다. 

델파이로 데이터베이스 프로그래밍을 할 때, 이 방식을 여러모로 매우 유용하게 사용할 수 있을 것이다.

이 방식은 TDate 또는 TDateTime 뿐만 아니라 모든 타입에서 사용할 수 있다. Integer, Double 등 일반 타입 뿐만 아니라 우리가 직접 만든 타입도 앞에 Nullable을 붙여서 사용할 수 있다.

멋진 점은 Nullable이 Record이기 때문에, 개발자가 메모리를 관리할 필요가 없다. 따라서 create하거나 Free하는 것을 신경쓰지 않아도 된다. 컴파일러가 알아서 관리한다. 

이 댓글 링크
다른 사이트에 공유하기

이 토의에 참여하세요

지금 바로 의견을 남길 수 있습니다. 그리고 나서 가입해도 됩니다. 이미 회원이라면, 지금 로그인하고 본인 계정으로 의견을 남기세요.

Guest
이 토픽(기고/질문)에 답하기

×   서식있는 텍스트로 붙여넣기.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   이전에 작성한 콘텐츠가 복원되었습니다..   편집창 비우기

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

중요한 정보

이용약관 개인정보보호정책 이용규칙 이 사이트가 더 잘 작동하기 위해 방문자의 컴퓨터에 쿠키가 배치됩니다. 쿠키 설정 변경에서 원하는 설정을 할 수 있습니다. 변경하지 않으면 쿠키를 허용하는 것으로 이해합니다.