'Midnight Peach'에 해당되는 글 25건

  1. 2012.06.04 v3.5 업데이트 - Entity Framework 지원, 솔루션 템플릿 업데이트
  2. 2012.06.04 Midnight Peach Quick Start Part II - Entity Framework 버전
  3. 2012.06.04 Codeplex 소스 호스팅과 팀 멤버 모집
  4. 2012.05.27 NetTcpBinding 을 위한 WCF 서비스의 구성
  5. 2012.05.23 Midnight Peach Quick Start Part II
  6. 2012.05.23 Midnight Peach Quick Start Part I
  7. 2012.05.23 Midnight Peach 배포
  8. 2011.02.11 생성된 코드로 보는 Midnight Peach 소개
  9. 2009.11.01 Midnight Peach의 필드 테스트와 개봉 박두
  10. 2009.03.25 Midnight Peach 2.0 샘플 애플리케이션, 웹 애플리케이션 (2/2)

v3.5 업데이트 - Entity Framework 지원, 솔루션 템플릿 업데이트

Midnight Peach 2012. 6. 4. 23:32

MP의 버전이 3.5로 업데이트 되었습니다.

이번 버전에서 크게 바뀐 점은 두 가지 입니다.

 

솔루션 템플릿 업데이트

기존 LINQ2SQL Basic, LINQ2SQL Use Service로 나뉘어져 있던 솔루션 템플릿을 LINQ to SQL 하나로 통합하였습니다.

또한 베타 버전으로 제공되던 Entity Framework 템플릿을 정식으로 지원합니다. (Entity Framework 지원에 대해서는 후술)

 

LINQ to SQL 솔루션 템플릿은 기존의 LINQ2SQL Use Service과 거의 동일합니다.

즉 WCF 서비스를 사용하는 형태의 아키텍쳐인데, 만일 WCF 서비스가 필요하지 않다면 아래와 같이 사용하지 않는 템플릿을 삭제하기만 하면 됩니다.

그림과 같이 DataAssembly 타입의 두 템플릿을 선택한 후 Delete 버턴을 누르면 삭제됩니다.

 

또한 이번 버전 부터는 솔루션 템플릿에도 버전이 부과됩니다.

현재는 두 솔루션 템플릿 모두 버전이 1.0 인데,  앞으로 솔루션 템플릿이 업데이트되면 이 버전 번호를 통해 알 수 있습니다.

 

Entity Framework 지원

MP의 오랜 숙원이었던 Entity Framework 이 이제 공식적으로 지원이 됩니다.

현재 지원하는 공식 버전은 Entity Framework 4.3 입니다.

EDMX 파일이 필요하므로, Code First 방식은 지원하지 않습니다.

Entity Framework에 대한 튜토리얼은 따로 포스팅을 하겠습니다.

:

Midnight Peach Quick Start Part II - Entity Framework 버전

Midnight Peach 2012. 6. 4. 23:30

0. DB 스키마 준비

파트 I과 동일한 스키마를 사용하니, 파트I을 참조하십시오.

1. 솔루션의 생성

MP를 실행한 후 Tool ?> Generate Solution을 실행합니다.

이번에는 Entity Framework 를 선택합니다.

생성된 솔루션을 비주얼 스튜디오에서 엽니다.

EntityFramework.dll 파일과 두 개의 T4 템플릿 파일이 포함되어 있습니다. (Memopad.Context.tt, Memopad.tt)

또한 4개의 프로젝트가 생성이 되는데 각 역할은 다음과 같습니다.

  • Test Console : 간단한 테스트용(단위 테스트와 상관 없음) 코드를 작성하기 위한 콘솔 프로젝트입니다.
  • Data : 데이터 엑세스 레이어입니다. EDMX 파일이 위치하고 있으며, 파트1의 Biz 프로젝트와 유사한 역할을 합니다.
  • Service : Data 프로젝트에서 만든 데이터 엑세스 메서드(MP가 생성한 코드 + 사용자가 만든 코드)를 래퍼하는 WCF 메서드가 있습니다.
  • Biz : Service 메서드를 호출하는 래퍼 메서드가 있습니다. Data와 Service 프로젝트와는 달리 클라이언트 측에 위치합니다.

아래 그림은 각 프로젝트 간의 실행 흐름입니다.

푸른색은 클라이언트에서 실행되는 코드, 붉은색은 (WCF가 실행되는) 서버에서 실행되는 코드입니다.

아주 중요한 그림이니 좀 있다 한번 더 말씀 드리겠습니다.

 

2. EDMX의 작성

생성된 EDMX 파일을 열고 Update Model from Database 를 선택합니다.

적절한 데이터 연결을 지정하거나 새로 만듭니다. 여기서는 파트I 에서 만든 Memopad DB를 계속 사용하겠습니다.

참고로 MySQL을 사용하기 위해서는 MySQL Connect를,  Oracle을 사용하기 위해서는 Oracle Data Access Components 를 미리 설치하여야 합니다.

추가할 테이블이나 뷰, 저장 프로시저를 선택합니다.

EDMX 파일을 저장하면 T4 템플릿 파일 (확장자가 tt)이 각 엔터티와 DbContext 파일들을 자동으로 생성합니다.

 

3. 데이터 레이어 코드 생성

서비스를 사용하는 솔루션에서는 MP가 두 단계의 코드를 생성합니다.

첫번째 단계는 EDMX 파일을 소스로 하여 데이터 엑세스 코드를 생성하는데, 파트I에서는 이 기능 만을 사용합니다.

두번째 단계는 Data 프로젝트를 빌드한 결과인 DLL (여기서는 Memopad.Data.DLL)을 소스로 하여, 이 DLL에 있는 메서드 들에 대한 래퍼 메서드를 생성하는 단계입니다.

 

먼저 첫번째 단계부터 진행을 하겠습니다.

MP에서 위에서 생성된 Memopad.mp 파일을 열고, Generate ?> Data (혹은 단축키 F1)을 실행하여 코드를 생성합니다.

Generated/Data.cs 파일을 열어 보면 많은 코드가 생성되어 있는 것을 볼 수 있습니다.

 

WCF 서비스를 사용하지 않는다면 여기까지만 해도 괜찮지만, 여기서는 WCF 서비스를 사용하는 두 번째 단계까지 진행을 해보겠습니다.

조금 더 실용적인 예제로 만들기 위하여 먼저 커스텀 메서드를 하나 추가해 보겠습니다.

Entities 폴더에 Memo 클래스를 추가하고 아래와 같이 코드를 작성합니다.

WCF 서비스를 통과해야 하므로 DataMember 특성을 추가하여야 합니다.

다음에는 Data 폴더에 MemoData 클래스를 추가하고 아래와 같이 코드를 작성합니다.

ForService 특성이 지정되어있는데, 이 특성은 MP로 하여금 이 메서드에 대한 서비스 레이어 코드를 생성하라는 것을 지시하는 역할을 합니다.

이제 비주얼 스튜디오에서 빌드를 하여 Memopad.Data.DLL을 생성합니다.

 

4. 서비스 레이어의 생성

다시 MP에서 Generate ?> Service (혹은 단축키 F2)를 실행하여, 서비스와 비지니스 코드를 생성합니다.

아래 그림과 같이 Biz 프로젝트에서 MP가 생성된 코드들을 추가합니다.

 

5. 솔루션 구성 테스트

솔루션이 적절히 구성되었는지 테스트를 할 차례입니다.

먼저 Memopad.Biz 프로젝트의 ServiceFactory.cs 파일을 열어 아래와 같이 코드를 작성합니다.

WCF 서비스가 배포된 주소를 지정하여야 하는데, 위 그림은 비주얼 스튜디오에 내장된 개발 서버를 사용하는 경우의 예입니다.

예에서는 54179 포트를 사용하는데 물론 사용자마다 다를 것입니다.

Memopad.Service 프로젝트의 속성 중 Web 탭에 있는 정보를 참고하여 적절한 포트번호를 지정하면 되겠습니다.

MP와 관련은 없지만, 비주얼 스튜디오의 내장된 개발 서버 대신 IIS Express를 사용하실 것을 적극 추천합니다.

Memopad.Service 프로젝트의 web.config 파일을 열어 DB 연결문자열을 적절히 수정합니다.

TestConsole 프로젝트의 Program.cs 파일에 아래 코드를 작성하여 솔루션이 제대로 구성되었는지 확인합니다.

TestConsole 프로젝트를 시작 프로젝트로 지정한 후 실행해서 예외가 발생하지 않고 정수 값이 출력되면 정상입니다.

 

6. 실행 흐름

이해를 돕기 위해 여기까지의 과정을 메서드의 실행흐름을 중심으로 정리해 보겠습니다.

클라이언트(즉 위에서는 TestConsole)에서 Bizrepository.Memo.GetCount 메서드를 호출하면 MemoBizBase 클래스의 GetCount 메서드가 호출됩니다.

이 메서드는 사용자 지정 비니지스 로직을 추가하기 위해 가상으로 지정되어 있습니다. (잠시 후에 좀 더 이야기를 해보겠습니다.)

그리고 ServiceFactory.GetService 메서드를 호출하여 IMemopadDataService ServiceContract 특성이 지정된 인터페이스를 구현한 객체를 생성합니다.

CreateBinding 메서드와 GetAddress 메서드는 각각 내부적으로 부분 메서드인 CreateBindingCore 와 GetAddressCore 를 호출하는데, 이 부분 메서드들을 사용자가 설정하면 각각 바인딩과 서비스의 주소를 재지정할 수 있습니다.

위에서 GetAddressCore 메서드를 구현한 것이 바로 주소를 지정하는 단계였습니다.

IMemopadDataService 인터페이스에는 데이터 엑세스 레이어의 메서드 중 ForService 특성이 붙은 메서드들이 모두 포함되어 있습니다.

위 그림에서 Memo_GetByCategoryName 은 사용자가 작성한 커스텀 메서드이고, Memo_GetByPK 는 MP가 자동 생성한 메서드 중 하나 입니다.

다시 Bizrepository.Memo.GetCount 메서드로 돌아가서, 서비스 객체를 만들고 나면 이를 이용해서 서비스 메서드를 호출합니다.

이 서비스 메서드 역시 MP가 생성하는데, 아래와 같습니다.

단순히 MemoData 클래스를 만든 후 GetCount() 메서드를 호출합니다.

MP가 만드는 기본 템플릿에는 서비스 메서드에 대한 인증 관련 코드가 빠져 있습니다.
실무에서는 인증 토큰이나 아이디와 패스워드를 전달하는 방법 등으로 인증을 해야할텐데, 이 경우에는 MP의 템플릿(확장자가 mp인 파일)을 수정하여야 합니다.
참고로 MP의 템플릿을 수정하기 위해서는 MP가 사용하는 매크로 언어인 MPML의 EBNF를 알아야 하는데, 이는 MP에서 볼 수 있습니다.
데이터 레이어를 만드는 EBNF에 대해서는 예전 포스트에서 설명한 적인 있는데, 서비스 레이어에 관해서는 아직 작성이 되어 있지 않습니다.

사실 MemoData 클래스에는 GetCount 메서드가 없습니다.

GetCount 메서드는 MemoData 의 부모 클래스인 EntityData<T> 에 저장되어 있습니다.

이 GetCount 메서드는 내부적으로 몇 개의 오버로드를 거치게 되는데 최종적으로 실행되는 메서드는 아래와 같습니다.

DbContext 객체를 생성하는 일을 하는 DbContext.Create 메서드를 제외하면, 모두 닷넷 프레임웍이 기본 제공하는 코드입니다.

그래서 MP가 생성한 코드는 여기가 마지막입니다.

 

6. 커스텀 비지니스 로직의 추가

커스텀 비지니스 로직을 추가하기 위해서는 각 엔터티의 BizBase 클래스를 상속 받는 클래스를 만들고 해당 메서드를 오버라이드 하여야 합니다.

사실 MP에는 이 BizBase 클래스를 상속 받는 클래스들이 이미 만들어져 있습니다.

이미 클래스가 만들어져 있으니, 동일한 이름으로 부분 클래스를 Memopad.Biz 프로젝트에 추가하고 아래와 같이 비지니스 로직을 추가합니다.

위 예에서는 단순히 파라미터의 유효성을 검사하는 코드를 추가하였습니다.

여기서 유심히 볼 부분은 바로 부모인 MemoBizBase 의 GetByCategoryName 메서드를 오버라이드하고, 커스텀 비지니스 로직 호출 전/후에 부모 클래스의 해당 메서드를 다시 호출하는 패턴이 되겠습니다.

 

7. 맺음말

MP는 단순한 코드가 아니라 프레임웍을 생성하는 것을 목표로 하고 있습니다.

그래서 비주얼 스튜디오의 솔루션 전체를 생성하는 기능을 제공하는 것인데, 이 솔루션에는 N-티어 아키텍쳐의 각 레이어에 해당하는 프로젝트들이 포함되어 있으며, 각 프로젝트에는 해당 프로젝트가 필요로 하는 어셈블리가 이미 참조되어 있고, 필수적으로 필요한 코드가 포함되어 있습니다.

물론 MP가 생성하는 솔루션의 아키텍쳐가 실무의 요구사항을 모두 만족하지는 않을 것입니다.

다만 MP는 N-티어 아키텍쳐와 LINQ에 익숙하지 않은 개발자에게, 솔루션을 어떻게 구성하고 어떤 코드를 어떤 레이어에 작성해야 하는가와 같은 문제에 대한 가이드 역할을 하고자 합니다.

온라인에서 글쓰기를 하면서 ‘지면관계상’ 이라는 말을 쓸 수는 없지만, MP를 설명하는 이 포스트에는 정말 많은 부분이 누락되어 있습니다.

관용적인 표현이 아니라, 정말로 열의 하나도 설명을 다 하지 못했습니다.

물론 MP를 만든 제가 친절하게 설명을 하는 것도 중요하지만, 결국에는 스스로 연구하고 습득하는 수 밖에 없을 것 같습니다.

이왕 MP를 공개까지 하였으니, 책임감을 느낌과 함께 가급적이면 개발자들의 공동체에 도움이 되었으면 합니다.

MP의 소스 코드 역시 곧 공개하겠습니다.

2012.6.4 업데이트
Codeplex 를 통해 소스가 공개되었습니다. 이 포스트를 참조하십시오.

MP 자체가 전 세계 개발자 공동체에서 제가 직간접적으로 전수 받은 지식으로 만들어진 것이니 당연한 일이겠지요.

 

본 튜토리얼의 예제 파일

Memopad.zip

:

Codeplex 소스 호스팅과 팀 멤버 모집

Midnight Peach 2012. 6. 4. 23:04

MP의 소스를 공개하기 위하여 Codeplex에서 MP를 호스팅하기로 하였습니다.

http://midnightpeach.codeplex.com/

설치 역시 Codeplex가 제공하는 클릭원스 배포를 활용하기로 하였습니다.

http://midnightpeach.codeplex.com/downloads/get/clickOnce/MidnightPeach.application

소스는 아래 링크에서 항상 최신 버전을 내려 받을 수 있습니다.

http://midnightpeach.codeplex.com/SourceControl/list/changesets

 

그리고 MP에 재능을 기부해주실 팀 멤버도 모집하고 있습니다.

관심이 있는 분은 cplkimth골뱅이hotmail.com 으로 메일을 주세요.

:

NetTcpBinding 을 위한 WCF 서비스의 구성

Midnight Peach 2012. 5. 27. 04:07

지난 포스트에서 이야기한 것과 같이 MP에는 WCF 서비스 코드와 그를 호출하는 코드를 생성하는 기능이 있습니다.

지난 포스트에서는 BasicHttpBinding 바인딩을 사용하는 사용했었는데, 오늘은 NetTcpBinding 을 사용하는 방법에 대해서 이야기를 해보겠습니다.

 

0. IIS 의 구성

BasicHttpBinding 은 IIS 에서 기본적으로 지원하지만, NetTcpBinding 은 별도의 호스팅 애플케이션이 필요합니다.

하지만 IIS 7.0 부터는 IIS 에서 HTTP 이외의 바인딩도 직접 호스팅하는 기능이 포함되어 있습니다.

IIS 에서 NetTcpBinding 을 지원하기 위해서는 먼저 이 글의 설명대로 IIS 를 구성하여야 합니다.

위 링크의 4번 단계 까지만 진행하고 나머지는 본 포스트의 설명을 계속 읽어주십시오.

 

1. web.config 파일 설정

지난 포스트에서 만든 Memopad 솔루션을 계속 예제로 사용하겠습니다.

MP가 생성한 Memopad.Service 프로젝트의  MemopadDataService.svc 파일을 열어 보면 마지막에 web.config 용 샘플이 생성되어 있습니다.

그 중에서 NetTcpBinding 부분을 복사하여 아래와 같이 web.config 파일에 붙여넣습니다.

바인딩의 여러 속성이 최대값으로 지정이 되어 있는데, 실 서버에 배포하기 전에는 적당히 조정을 하여야 합니다.

 

2. 서비스 클라이언트의 구성

Memopad.Biz 프로젝트의 Biz.cs 파일에는 역시 WCF 서비스 클라이언트용의 샘플 코드가 있습니다.

지난 번에 설명한대로 ServiceFactory 클래스를 만들고 위 샘플 코드에서 아래와 같은 두 메서드를 복사합니다.

주소가 localhost 로 되어 있는데, NetTcpBinding 은 BasicHttpBinding 과 달리 비주얼 스튜디오의 내장 웹 서버가 호스팅 할 수가 없습니다.

따라서 별도의 호스트 애플리케이션을 만들어야 하는데, 자세한 설명은 MSDN의 설명을 참고하십시오.

여기서는 실 서버의 IIS 에 호스팅하는 예를 보이겠습니다.

 

3. 서비스의 게시

솔루션 탐색기에서 Memopad.Service 프로젝트를 우클릭하고 게시를 선택합니다.

실서버에 서비스를 게시할 수 있는 방법을 지정하여야 하는데, 여기서는 FTP 를 사용하였습니다.

FTP 의 주소는 적절한 값으로 설정하시기 바랍니다.

여기서는 ftp://실서버의 IP/Memopad.Service 라고 설정하였습니다.

게시가 끝났으면 실서버에서 IIS 관리자를 실행한 후 방금 게시된 가상 디렉토리를 응용 프로그램으로 변환하여야 합니다.

이 때 주의할 점은 응용 프로그램 풀이 Memopad.Service 가 사용하는 닷넷프레임웍 버전을 지원하여야 한다는 것입니다.

이 예제에서는 Memopad.Service 가 닷넷프레임웍 4.0을 사용하므로 닷넷프레임웍 4.0 응용 프로그램 풀을 지정하였습니다.

마지막으로 위 응용 프로그램이 NetTcpBinding 을 지원하도록 설정하여야 합니다.

위 응용 프로그램의 고급 설정 창을 연 후, 사용할 수 있는 프로토콜을 아래와 같이 설정합니다.

이제 IIS 설정이 모두 끝났습니다.

다시 Memopad.Biz 프로젝트로 돌아가 (사용자가 생성한) ServiceFactory 클래스를 열어 WCF 서비스의 주소를 방금 게시한 주소를 변경합니다.

net.tcp://실서버의 IP/Memopad.Service/MemopadDataService.svc 와 같은 식으로 지정하면 됩니다.

 

4. 테스트

모든 작업을 마쳤으니 제대로 동작하는지 테스트를 해봅시다.

Memopad.TestConsole 프로젝트의 Program.cs 파일에 아래와 같은 코드를 작성합니다.

예외가 발생하지 않고 정수가 출력되면 모든 것이 정상입니다.

복습 삼아 지난 시간에 한 이야기를 다시 하자면, Memopad.Biz 프로젝트의 등록정보에서 ForService 라는 기호가 정의되어 있을 때에만 WCF 서비스를 호출합니다.

(정의되어 있지 않으면 서비스를 호출하는 대신 DB에 바로 접속합니다.)

따라서, Memopad.Biz 프로젝트에 ForService 가 정의되어 있고, Memopad.TestConsole 프로젝트의 app.config 파일에 DB 연결문자열이 없는 상태에서,

위 Program.cs 파일의 테스트 코드가 작동한다면, WCF 서비스가 제대로 구축되어 있다고 할 수 있겠습니다.

본 포스트의 샘플 파일 :

Memopad.zip

:

Midnight Peach Quick Start Part II

Midnight Peach 2012. 5. 23. 23:21

본 포스트는 Midnight Peach 3.x 버전의 빠른 설명서입니다.

본 포스트는 두 개의 파트로 이루어져 있습니다.

파트 I에서는 서비스 레이어(WCF)를 두지 않는 형태(즉, 클라이언트에서 DB에 바로 붙는 경우)를 다루고, 파트 II에서는 서비스 레이어를 포함하는 구조에 대해서 각각 설명합니다.

 

0. DB 스키마 준비

파트 I과 동일한 스키마를 사용하니, 파트I을 참조하십시오.

 

1. 솔루션의 생성

MP를 실행한 후 Tool –> Generate Solution을 실행합니다.

image

이번에는 LINQ2SQL Use Service를 선택합니다.

생성된 솔루션을 비주얼 스튜디오에서 엽니다.

image

4개의 프로젝트가 생성이 되는데 각 역할은 다음과 같습니다.

  • Test Console : 간단한 테스트용(단위 테스트와 상관 없음) 코드를 작성하기 위한 콘솔 프로젝트입니다.
  • Data : 데이터 엑세스 레이어입니다. DBML 파일이 위치하고 있으며, 파트1의 Biz 프로젝트와 유사한 역할을 합니다.
  • Service : Data 프로젝트에서 만든 데이터 엑세스 메서드(MP가 생성한 코드 + 사용자가 만든 코드)를 래퍼하는 WCF 메서드가 있습니다.
  • Biz : Service 메서드를 호출하는 래퍼 메서드가 있습니다. Data와 Service 프로젝트와는 달리 클라이언트 측에 위치합니다.

아래 그림은 각 프로젝트 간의 실행 흐름입니다.

image

푸른색은 클라이언트에서 실행되는 코드, 붉은색은 (WCF가 실행되는) 서버에서 실행되는 코드입니다.

아주 중요한 그림이니 좀 있다 한번 더 말씀 드리겠습니다.

 

2. DBML의 작성

역시 파트I과 동일합니다.

 

3. 데이터 레이어 코드 생성

서비스를 사용하는 솔루션에서는 MP가 두 단계의 코드를 생성합니다.

첫번째 단계는 DBML 파일을 소스로 하여 데이터 엑세스 코드를 생성하는데, 파트I에서는 이 기능 만을 사용합니다.

두번째 단계는 Data 프로젝트를 빌드한 결과인 DLL (여기서는 Memopad.Data.DLL)을 소스로 하여, 이 DLL에 있는 메서드 들에 대한 래퍼 메서드를 생성하는 단계입니다.

먼저 첫번째 단계부터 진행을 하겠습니다.

MP에서 위에서 생성된 Memopad.mp 파일을 열고, Generate –> Data를 실행하여 코드를 생성합니다.

솔루션탐색기에서 Show All Files 버튼을 클릭하여 MP가 생성한 파일을 표시합니다.

image

Generated 폴더에서 오른쪽 버튼을 클릭한 후 Include In Project를 선택합니다.

image

두번째 단계를 진행하기 위해 먼저 커스텀 메서드를 만들어 보겠습니다.

Entities 폴더에 Memo 클래스를 추가하고 아래와 같이 코드를 작성합니다.

image

WCF 서비스를 통과해야 하므로 DataMember 특성을 추가하여야 합니다.

다음에는 Data 폴더에 MemoData 클래스를 추가하고 아래와 같이 코드를 작성합니다.

image_thumb[27]

ForService 특성이 지정되어있는데, 이 특성은 MP로 하여금 이 메서드에 대한 서비스 레이어 코드를 생성하라는 것을 지시하는 역할을 합니다.

이제 비주얼 스튜디오에서 빌드를 하여 Memopad.Data.DLL을 생성합니다.

 

4. 서비스 레이어의 생성

다시 MP에서 Generate –> Service 를 실행하여, 서비스와 비지니스 코드를 생성합니다.

코드를 생성하고 나면 아래와 같은 메시지 박스가 나오는데, 이는 현재 MP의 해결하지 못한 버그입니다.

image

[2012.6.1 업데이트]

위 버그는 3.0.15 버전에서 수정되었습니다.

아래 그림과 같이 Biz 프로젝트에서 MP가 생성된 코드들을 추가합니다.

image

 

5. 솔루션 구성 테스트

솔루션이 적절히 구성되었는지 테스트를 할 차례입니다.

먼저 Memopad.Biz 프로젝트에 ServiceFactory 클래스를 추가하고 아래와 같이 코드를 작성합니다.

image

WCF 서비스가 배포된 주소를 지정하여야 하는데, 위 그림은 비주얼 스튜디오에 내장된 개발 서버를 사용하는 경우의 예입니다.

예에서는 54179 포트를 사용하는데 물론 사용자마다 다를 것입니다.

Memopad.Service 프로젝트의 속성 중 Web 탭에 있는 정보를 참고하여 적절한 포트번호를 지정하면 되겠습니다.

image 

MP와 관련은 없지만, 비주얼 스튜디오의 내장된 개발 서버 대신 IIS Express를 사용하실 것을 적극 추천합니다.

Memopad.Service 프로젝트의 web.config 파일을 열어 DB 연결문자열을 적절히 수정합니다.

image

TestConsole 프로젝트의 Program.cs 파일에 아래 코드를 작성하여 솔루션이 제대로 구성되었는지 확인합니다.

image

TestConsole 프로젝트를 시작 프로젝트로 지정한 후 실행해서 예외가 발생하지 않고 정수 값이 출력되면 정상입니다.

 

6. 실행 흐름

이해를 돕기 위해 여기까지의 과정을 메서드의 실행흐름을 중심으로 정리해 보겠습니다.

클라이언트(즉 위에서는 TestConsole)에서 Bizrepository.Memo.GetCount 메서드를 호출하면 MemoBizBase 클래스의 GetCount 메서드가 호출됩니다.

image

이 메서드는 사용자 지정 비니지스 로직을 추가하기 위해 가상으로 지정되어 있습니다. (잠시 후에 좀 더 이야기를 해보겠습니다.)

그리고 ServiceFactory.GetService 메서드를 호출하여 IMemopadDataService ServiceContract 특성이 지정된 인터페이스를 구현한 객체를 생성합니다.

image

CreateBinding 메서드와 GetAddress 메서드는 각각 내부적으로 부분 메서드인 CreateBindingCore 와 GetAddressCore 를 호출하는데, 이 부분 메서드들을 사용자가 설정하면 각각 바인딩과 서비스의 주소를 재지정할 수 있습니다.

위에서 GetAddressCore 메서드를 구현한 것이 바로 주소를 지정하는 단계였습니다.

IMemopadDataService 인터페이스에는 데이터 엑세스 레이어의 메서드 중 ForService 특성이 붙은 메서드들이 모두 포함되어 있습니다.

image

위 그림에서 Memo_GetByCategoryName 은 사용자가 작성한 커스텀 메서드이고, Memo_GetByPK 는 MP가 자동 생성한 메서드 중 하나 입니다.

다시 Bizrepository.Memo.GetCount 메서드로 돌아가서, 서비스 객체를 만들고 나면 이를 이용해서 서비스 메서드를 호출합니다.

image

이 서비스 메서드 역시 MP가 생성하는데, 아래와 같습니다.

image

단순히 MemoData 클래스를 만든 후 GetCount() 메서드를 호출합니다.

MP가 만드는 기본 템플릿에는 서비스 메서드에 대한 인증 관련 코드가 빠져 있습니다.
실무에서는 인증 토큰이나 아이디와 패스워드를 전달하는 방법 등으로 인증을 해야할텐데, 이 경우에는 MP의 템플릿(확장자가 mp인 파일)을 수정하여야 합니다.
참고로 MP의 템플릿을 수정하기 위해서는 MP가 사용하는 매크로 언어인 MPML의 EBNF를 알아야 하는데, 이는 MP에서 볼 수 있습니다.
데이터 레이어를 만드는 EBNF에 대해서는 예전 포스트에서 설명한 적인 있는데, 서비스 레이어에 관해서는 아직 작성이 되어 있지 않습니다.

사실 MemoData 클래스에는 GetCount 메서드가 없습니다.

GetCount 메서드는 MemoData 의 부모 클래스인 EntityData<T> 에 저장되어 있습니다.

이 GetCount 메서드는 내부적으로 몇 개의 오버로드를 거치게 되는데 최종적으로 실행되는 메서드는 아래와 같습니다.

image

DbContext 객체를 생성하는 일을 하는 DataContextFacotry.Create 메서드를 제외하면, 모두 닷넷 프레임웍이 기본 제공하는 코드입니다.

그래서 MP가 생성한 코드는 여기가 마지막입니다.

 

6. 커스텀 비지니스 로직의 추가

커스텀 비지니스 로직을 추가하기 위해서는 각 엔터티의 BizBase 클래스를 상속 받는 클래스를 만들고 해당 메서드를 오버라이드 하여야 합니다.

사실 MP에는 이 BizBase 클래스를 상속 받는 클래스들이 이미 만들어져 있습니다.

image

이미 클래스가 만들어져 있으니, 동일한 이름으로 부분 클래스를 Memopad.Biz 프로젝트에 추가하고 아래와 같이 비지니스 로직을 추가합니다.

image

image

위 예에서는 단순히 파라미터의 유효성을 검사하는 코드를 추가하였습니다.

여기서 유심히 볼 부분은 바로 부모인 MemoBizBase 의 GetByCategoryName  메서드를 오버라이드하고, 커스텀 비지니스 로직 호출 전/후에 부모 클래스의 해당 메서드를 다시 호출하는 패턴이 되겠습니다.

 

7. 맺음말

MP는 단순한 코드가 아니라 프레임웍을 생성하는 것을 목표로 하고 있습니다.

그래서 비주얼 스튜디오의 솔루션 전체를 생성하는 기능을 제공하는 것인데, 이 솔루션에는 N-티어 아키텍쳐의 각 레이어에 해당하는 프로젝트들이 포함되어 있으며, 각 프로젝트에는 해당 프로젝트가 필요로 하는 어셈블리가 이미 참조되어 있고, 필수적으로 필요한 코드가 포함되어 있습니다.

물론 MP가 생성하는 솔루션의 아키텍쳐가 실무의 요구사항을 모두 만족하지는 않을 것입니다.

다만 MP는 N-티어 아키텍쳐와 LINQ에 익숙하지 않은 개발자에게, 솔루션을 어떻게 구성하고 어떤 코드를 어떤 레이어에 작성해야 하는가와 같은 문제에 대한 가이드 역할을 하고자 합니다.

 

온라인에서 글쓰기를 하면서 ‘지면관계상’ 이라는 말을 쓸 수는 없지만, MP를 설명하는 이 포스트에는 정말 많은 부분이 누락되어 있습니다.

관용적인 표현이 아니라, 정말로 열의 하나도 설명을 다 하지 못했습니다.

물론 MP를 만든 제가 친절하게 설명을 하는 것도 중요하지만, 결국에는 스스로 연구하고 습득하는 수 밖에 없을 것 같습니다.

이왕 MP를 공개까지 하였으니, 책임감을 느낌과 함께 가급적이면 개발자들의 공동체에 도움이 되었으면 합니다.

MP의 소스 코드 역시 곧 공개하겠습니다.

2012.6.4 업데이트
Codeplex 를 통해 소스가 공개되었습니다. 이 포스트를 참조하십시오.

MP 자체가 전 세계 개발자 공동체에서 제가 직간접적으로 전수 받은 지식으로 만들어진 것이니 당연한 일이겠지요.

:

Midnight Peach Quick Start Part I

Midnight Peach 2012. 5. 23. 23:20

본 포스트는 Midnight Peach 3.x 버전의 빠른 설명서입니다.

본 포스트는 두 개의 파트로 이루어져 있습니다.

파트 I에서는 서비스 레이어(WCF)를 두지 않는 형태(즉, 클라이언트에서 DB에 바로 붙는 경우)를 다루고, 파트 II에서는 서비스 레이어를 포함하는 구조에 대해서 각각 설명합니다.

 

0. DB 스키마 준비

먼저 DB 스키마가 구성되어 있어야 할 것입니다.

여기서는 Memopad 라는 데이터베이스를 만들어 사용하겠습니다.

아래 파일은 위 스키마에 대한 생성 스크립트입니다.

invalid-file

 

1. 솔루션의 생성

MP에는 비주얼 스튜디오 솔루션 템플릿이 내장되어 있습니다.

이 기능을 이용하면, MP가 추천하는 형태대로 프로젝트가 미리 구성된 솔루션을 쉽게 생성할 수 있습니다.

MP를 실행시킨 후 Tool –> Generate Solution 을 실행합니다.

image

Template은 LINQ2SQL Basic, Solution Name은 생성할 솔루션 이름, Folder는 솔루션을 생성할 폴더를 지정한 후, OK 버튼을 누릅니다.

image

솔루션을 생성하고 나면 비주얼 스튜디오에서 열겠냐고 물어보는데, 예를 선택하여 솔루션을 엽니다.

image

두 개의 프로젝트가 생성되는데, Memopad.Biz는 데이터 액세스 레이어와 비지니스 레이어가 결합된 프로젝트이고, Memopad.TestConsole 프로젝트는 Biz 프로젝트를 테스트하기 위한 용도의 콘솔 프로젝트입니다.

Memopad.mp 파일은 MP의 템플릿 파일입니다.

Biz와 Entities 폴더는 각각 사용자가 작성하는 비지니스 클래스와 엔터티 클래스가 들어갈 곳입니다. (DeleteMe.txt 파일들은 부모 폴더를 생성하기 위해 만든 더미 파일이니 삭제하시면 됩니다.)

Generated 폴더 안에는 MP가 생성할 코드가 들어갈 곳입니다. 이 폴더 안의 코드는 개발자가 직접 수정하지 않아야 합니다.

 

2. DBML의 작성

(비주얼 스튜디오에서) Memopad.dbml 파일을 열고 서버 탐색기에서 Memo 테이블과 Category 테이블을 끌어옵니다.

image

N-Tier에서 LINQ-toSQL를 사용하기 위해서는 각 엔터티 프로퍼티의 Update Check 값이 Never로 설정이 되어야 합니다.

아래는 Memo 엔터티중 MemoID 프로퍼티의 예인데, 이런 식으로 모든 프로퍼티가 설정되어야 합니다.

image

엔터티와 프로퍼티 수가 많으면 제법 번거로운 작업이 될 수 있는데, MP에는 이 작업을 쉽게 할 수 있는 기능도 내장되어 있습니다.

MP에서 Tool –> Add Update Check를 실행한 후, 위 DBML 파일을 선택합니다.

image

여기서 중요한 점이 있는데, 위와 같이 Update Check를 설정한 후에는 반드시 비주얼 스튜디오에서 DBML 파일을 다시 열고 나서 저장을 해야 한다는 것입니다.

그렇게 해야 Update Check 값이 Never가 지정된 상태에서 비주얼 스튜디오가 코드를 생성합니다.

 

3. MP의 코드 생성

MP에서 위에서 생성된 Memopad.mp 파일을 열고, Generate –> Data를 실행하여 코드를 생성합니다.

image

이제 MP에 의해 생성된 코드가 Generated 폴더 안에 생겼습니다.

이 시점에서 솔루션이 제대로 구성되었는지 테스트를 해볼 수 있습니다.

TestConsole 프로젝트를 시작 프로젝트로 설정한 후 app.config 파일을 열어 아래와 같이 DB 연결 문자열을 수정합니다.

image

Program.cs 파일을 연 후 아래 코드를 입력한 후 프로젝트를 실행합니다.

image

별다른 예외가 발생하지 않고 정수값이 출력되면 성공입니다.

 

4. 커스텀 비지니스 클래스의 작성

위 단계에서 각 엔터티 마다 20개 이상의 데이터 엑세스 메서드가 생성이 되었습니다.

특히 Get 메서드의 경우 필터링 / 정렬 / 페이징을 각각 포함하는 8개의 오버로드가 제공되어 바로 사용할 수도 있지만, 여기서는 Memo 엔터티에 대한 커스텀 메서드를 하나 만들어 보겠습니다.

만들려고 하는 메서드는 아래와 같습니다.

image

카테고리 이름을 검색 조건으로 하여 Memo 엔터티를 검색하는 메서드인데, 이때 반환되는 각 Memo 엔터티에는 카테고리 이름이 포함되어 있습니다.

즉 다음과 같은 쿼리를 실행하는 메서드입니다.

image

먼저 Memo 엔터티가 카테고리 이름을 가져야 하므로 Memo 엔터티에 CategoryName 이라는 속성을 추가해야 합니다.

물론 Memo 클래스는 DBML을 저장할 때 비주얼 스튜디오가 생성하는 코드이므로, 여기서는 부분 클래스로 만들어야 합니다.

Entities 폴더 안에 Memo 클래스를 추가합니다.

image

(이 스샷은 조금 있다 사용할 MemoBiz 클래스도 같이 추가해 둔 상태입니다.)

새로 만든 Memo 클래스를 부분 클래스로 지정하고 CategoryName 프로퍼티를 정의합니다.

image

네임스페이스를 기존 Memo 클래스와 동일하게 맞추고, partial 키워드를 지정합니다.

이번에는 MemoBiz 클래스를 추가하고 아래와 같이 LINQ 코드를 작성합니다.

image

역시 네임스페이스를 맞추고 partial 키워드를 지정합니다.

위 코드에서 쿼리 내용에 대해서는 여러 가지 이야기할 포인트가 많으니, 별도의 포스트에서 다루도록 하겠습니다.

 

여기까지 해서 서비스 레이어를 두지 않는 형태의 솔루션을 만들어 봤습니다.

다음 포스트에서는 서비스 레이어를 생성하는 형태에 대해서 이야기해 보겠습니다.

:

Midnight Peach 배포

Midnight Peach 2012. 5. 23. 00:58

 

2012.6.4 업데이트

MP의 소스를 공개하면서 배포 방법도 변경되었습니다. Codeplex 소스 호스팅과 팀 멤버 모집 포스트를 참고하십시오.

3년 이상 필드에서 사용하며 계속 다듬었더니 이제 공개할 만한 수준이 된 것 같습니다.
오래 기다리셨습니다.

현재 버전은 3.0.12 입니다. 그래서 처음 설치하면 3.0.12 버전이 설치가 되는데, 재실행 하면 최신 버전으로 업데이트가 됩니다.

 

Midnight Peach에 관한 예전 포스트들은 1.X대 혹은 2.X대 버전에 맞춰진 것들이 많아, 현재 버전과 맞지 않는 내용이 많습니다.
이제 공식적으로 배포도 시작하고 했으니, 가급적 빨리 업데이트를 하도록 하겠습니다.

:

생성된 코드로 보는 Midnight Peach 소개

Midnight Peach 2011. 2. 11. 10:19

[주의]
이 글은 MP의 현재 버전 (3.X)에 맞지 않습니다.

단순 참고용으로만 활용하십시오

Northwind의 몇 개의 테이블을 가지고 진행을 해보겠습니다.

아시다시피 Northwind DB에는 고객, 주문, 제품 테이블들이 있는 이들은 아래와 같은 관계를 가지고 있습니다.

그리고 페이징을 지원하며, 제품 이름과 고객 이름을 검색 조건으로 하고 제품 정보를 반환하는 GetForCompany 라는 메서드가 있다고 가정을 해봅시다.

간단하지만 이 쿼리에는 몇 가지 이슈가 포함되어 있습니다.

A. 여러 단계의 조인(inner / outer)을 사용합니다.

B. 검색 조건에 따라 서로 다른 쿼리를 생성하는 이른바 동적 쿼리가 포함되어 있습니다.

C. 엔터티의 모든 멤버가 아니라 특정 멤버만 반환하는 프로젝션이 필요합니다.

D. 페이징을 지원합니다.

통상적으로 윈폼 환경에서는 클라이언트(윈폼)과 서버(DB) 사이에 미들티어(WCF 서비스 등)을 두게 됩니다.

따라서 위 메서드를 호출하기 위해서는 위 메서드를 WCF 서비스로 만들고 클라이언트에서 이를 호출하여야 합니다.

MP를 이용하면 이 메서드를 3 티어 환경에서 사용하기 위한 코드를 자동으로 생성할 수 있습니다.

즉, 서비스 메서드 등을 따로 만들 필요가 없이 아래와 같이 클라이언트에서 바로 이 메서드를 호출하면 됩니다.

MP는 WCF 서비스가 있는 경우와 없는 경우(즉, 클라이언트가 DB 서버에 바로 연결되는 경우)를 모두 지원하며, 아무런 코드 수정 없이 두 경우를 자유롭게 변경할 수 있습니다.
위 코드와 같이 릴리즈 모드에서만 BizRepository.ActivateService 메서드가 호출되도록 구성해놓으면, 디버그 모드에서는 DB에 바로 접속을 하고, 릴리즈 모드에서는 WCF 서비스를 사용하도록 할 수 있습니다.

아래 그림은 각 경우에 있어서 메서드들 간의 호출순서를 표현한 것입니다.

하늘색은 DB에 바로 접속하는 경우이며 주황색은 WCF 서비스를 경유하는 경우인데, ‘경계통과’ 라 함은 각 경우에 있어 실행 흐름이 클라이언트에서 서버로 넘어가는 것을 말합니다.

그림에서 보다시피 두 경우는 ProductBiz에서 갈라지는데, 이는 ProductBiz가 ProductData 객체를 가지고 있느냐, 아니면 ProductData를 상속 받은 ProductServiceData 객체를 가지고 있느냐에 달려 있습니다.

이를 결정하는 것이 바로 BizRepository.ActivateService 메서드가 하는 일입니다.

 

위 그림을 염두에 두고, MP가 생성하는 코드들을 살펴보면 다음과 같습니다.

1. 각 엔터티에 대해 30가지 이상의 기본 메서드를 생성합니다.

A. 조건식과 정렬식과 페이징을 지원하는 Get 메서드 (8개의 오버로드)

예컨데, ‘재고 수가 10개 이상인 상품을 이름순으로 5개를 가져오는 쿼리’는 아래와 같은 람다식을 사용하면 바로 실행할 수 있습니다.

B. 엔터티의 PK를 검색 조건으로 하는 GetSingle 메서드

C. 조건식과 정렬식을 지정하여 첫번째 혹은 마지막 원소를 반환하는 메서드 (각 4개의 오버로드)

D. 조건식에 해당하는 엔터티의 갯수를 구하는 메서드 (4개의 오버로드)

E. 하나의 엔터티를 삽입/수정/삭제하는 메서드 (각 2개의 오버로드)

F. 트랜잭션을 지원하며 엔터티의 컬렉션을 삽입/수정/삭제하는 메서드 (각 2개의 오버로드)

2. 각 엔터티에 대해 다양한 헬퍼 코드를 생성합니다.

A. 기본값이 지정된 생성 메서드

B. 복사 메서드

C. 부분 메서드를 사용하여 재정의가 가능한 ToString 메서드

D. IEditableObject 인터페이스 구현

E. 속성 이름에 대한 상수값과 열거형 타입

F. 엔터티의 PK를 사용하여 엔터티의 동등성을 비교하는 IEqualityComparer 인터페이스를 구현

3. WCF 서비스를 위한 코드를 생성합니다.

A. 서비스 메서드 (ProductService.GetForCompany)

B. 서비스 메서드를 호출 래퍼 (ProductServiceData.GetForCompany)

C. 비지니스 레이어 메서드(ProductBiz.GetForCompany)

:

Midnight Peach의 필드 테스트와 개봉 박두

Midnight Peach 2009. 11. 1. 04:31

[주의]
이 글은 MP의 현재 버전 (3.X)에 맞지 않습니다.

단순 참고용으로만 활용하십시오

2009.7.20 일이 마지막 포스팅 날짜니, 근 백일 만의 포스팅이 되네요.

물론 짐작하시다시피, 화끈한 프로젝트에 한 발 수준이 아니라 온 몸을 푸욱 담그고 있었던 게 백일 간의 은둔의 변명이 맞습니다.

 

그 동안 로피스 플러스라는 제품을 만들었었는데요. 대형 로펌 (물론 개인 법률 사무소도)의 거의 모든 법률 업무를 처리할 수 있는 일종의 ERP 솔루션입니다.

개발 과정에서 프로그래밍에 대하여 좀 더 알게 된 부분도 많고, 몇 가지 디자인 패턴과 라이브러리를 개발하기도 하는 등, 나름 뜻 깊은 프로젝트였습니다만, 그 중 가장 큰 의미가 있는 것은 아무래도 Midnight Peach의 필드 테스트를 성공적으로 수행한 것이 아닌가 싶습니다.

 

테이블이 백여개 정도 되는 제법 규모가 있는 솔루션임에도 불구하고 LINQ와 MP를 사용하니, 데이터베이스 핸들링 작업, 즉 데이터 액세스 레이어는 날로 먹다시피 했습니다.

예를 들어 아래는 사건 검색 컨트롤 입니다.

각각 AND 조건으로 결합되는 14가지의 검색 조건이 있습니다. 그리고 결과는 8개의 테이블에서 뽑아 오는데, 이 중 일부는 두 단계 혹은 세 단계의 조인을 거쳐야 합니다.

LINQ를 사용할 수 없다면, 각각의 검색 조건을 매개변수로 받아 동적으로 쿼리를 조립하는 프로시저(동적 쿼리 프로시저)를 만드는 게 최선(어쩌면 유일?)일 것 같은데요.

아마도 이 프로시저의 길이는 족히 몇 백 라인, 어쩌면 천 라인이 넘을 것 같습니다.

 

이런 끔찍한 동적 쿼리 프로시저는 생각만 해도 예전 기억이 떠올라 경기를 일으킬 분이 많으실 것 같은데요, 굳이 상처를 헤집어 소금을 뿌리는 심정으로 문제점들을 이야기해보자면,

  1. 유지보수가 극히 어렵습니다. 특히 작성자가 다른 사람이라면 불가능에 가깝다고도 할 수 있습니다.
  2. 코드의 가독성이 무척 낮아, 코드 파악이 힘듭니다.
  3. 동적으로 쿼리를 조립하는 형태이므로, 컴파일 타임의 체크가 불가능합니다. 특히나 인텔리센스의 도움을 받을 수 없기 때문에 몇 천 라인 중에 오타 한 글자만 있더라도 실행 전까지는 알 수 없습니다.
  4. 디버깅이 불가능하거나 극히 어렵습니다.
  5. 저장 프로시저임에도 불구하고 실행계획을 저장할 수 없기 때문에, 동적 쿼리가 아닌 프로시저나 parameterized 쿼리에 비해 성능이 좋지 않습니다.
  6. 따로 방비를 하지 않으면 SQL injection 공격에 취약합니다.

 

하지만 이 모든 문제가 LINQ를 사용하면 해결이 됩니다.

물론 LINQ 자체가 가진 장단이 있고, LINQ에 대한 각 개발자의 호오가 분명 있을 테지만, 적어도 위에서 말한 말 그대로 ‘끔찍한’ 동적 쿼리 프로시저를 만들지 않아도 된다면, LINQ는 충분히 고려해볼 만한 가치가 있는 기술이라는 생각이 듭니다.

 

참고로, 단순 비교하기에는 무리가 있겠지만, 위의 검색 메서드를 MP가 생성한 프레임웍의 도움을 받아 LINQ로 구현하는 데 한 시간이 채 걸리지 않았습니다. 라인 수도 70 라인 정도로 짧았고요.

(사족이지만, 이는 제가 평생 만든 메서드 중 가장 긴 것인데, 사실 70 라인도 개발자가 직관적으로 코드를 장악하기에는 긴 편입니다.)

 

DataReader를 이용한 저수준(수동) 구현, 형식 있는 (혹은 없는) 데이터셋의 사용, 데이터셋 대신 비지니스 오브젝트 (엔터티)를 사용하되 Data Access Application Block과 같은 라이브러리나 NetTiers 같은 코드 생성기의 도움을 받는 방법, CSLA.NET과 같은 프레임웍의 도입, NHibernate 같은 ORM 툴 까지, 그간 데이터 액세스 레이어를 구축하는 데 있어 참 많은 기술들을 사용하여 보았습니다.

하지만 이번 프로젝트에서의 적용을 통해 저는 LINQ가 이 모든 기술의 정점에 있다는 확신을 가지게 되었습니다.

정점에 있다니까 ‘유사한 것 중 최고’ 라는 느낌이 드는데, LINQ는 다른 기술들과 본질적으로 다릅니다. 그래서 ‘더 좋다’가 아니라 패러다임 자체가 다르다고 표현해야 되지 않을까 싶습니다.

 

아주 추상화시켜서 이야기하자면, 프로그램 언어는 데이터와 이에 대한 연산으로 이루어져 있습니다.

이 중 데이터는 메모리의 휘발성 때문에 저장소에 영속화(persistent) 되어야 할 필요가 있는데, 이 저장소에는 여러가지가 있습니다.

우리가 필드에서 개발하는 대부분의 응용 프로그램들은 DBMS를 저장소로 사용하지만, 이는 파일 시스템이 될 수도 있고, 네트웍을 통해 들어오는 스트림이 될 수도 있습니다.

그렇다면 프로그램이 데이터를 연산하기 위해서는 저장소에 있는 데이터를 메모리로 가져와야 하는데(쿼리), 저장소가 무엇이냐에 따라 이 쿼리 방법이 너무나 상이하고, 또 프로그램 언어 자체에는 이 기능이 없다는 것이 문제가 됩니다.

(예컨데, DataSet을 통해 DB의 데이터를 가져오는 것은 C#의 기능이 아닙니다. FileStream 라이브러리를 통해 파일의 데이터를 가져오듯이, DataSet 클래스 라이브러리를 통해 DB에 접근하는 것이지요)

 

LINQ의 목표는 이 상이한 데이터 쿼리 방법들을 언어 자체의 기능으로 통합하는 것이고, LINQ의 정식 명칭인 Language INtegrated Query가 의미하는 바도 바로 이것입니다.

그리고 C#의 설계자인 Anders Hejlsberg가 LINQ에 대해 인터뷰하면서 ‘(LINQ는) 쿼리와 집합(역주:데이터) 연산을 닷넷 언어의 주요 구성 요소로 만든다’고 한 말도 이런 맥락에서 이해할 수 있겠습니다.

(http://channel9.msdn.com/posts/scobleizer/Anders-Hejlsberg-LINQ/)

 

필드 테스트를 통해 MP의 안정성이라던가 사용편의성 같은 것들을 체크해 보았으니, 이제 MP를 발표할 때가 된 것 같습니다.

여태까지는 블로그에만 포스팅을 하고 외부에는 일절 알리지 않고 있는데, 블로그에도 아직 MP의 기능 반 정도가 소개되지 않았습니다.

모든 기능에 대한 매뉴얼과 MP를 사용한 샘플 애플리케이션 정도만 준비되면 공식적으로 발표를 할 생각입니다.

기대해 주세요.

:

Midnight Peach 2.0 샘플 애플리케이션, 웹 애플리케이션 (2/2)

Midnight Peach 2009. 3. 25. 23:43

[주의]
이 글은 MP의 현재 버전 (3.X)에 맞지 않습니다.

단순 참고용으로만 활용하십시오

Midnight Peach 2.0 샘플 애플리케이션, 웹 애플리케이션 (1/2)에 이어서 계속 진행하겠습니다.

데이터베이스 연결 문자열

web.config 파일을 열어 데이터베이스 연결 문자열을 설정합니다.

image

여기서 연결 문자열의 이름은 아무렇게나 지정해서는 안됩니다.

MP의 아래 화면에서 지정한 이름과 동일해야 하는데, 여기서는 Memopad로 지정되어 있습니다.

image

연결 문자열을 설정하였으면 DB에 제대로 연결이 되고 생성된 비지니스 레이어에 문제가 없는지 간단히 테스트를 해보도록 합시다.

Default.aspx 파일에 아래와 같은 코드를 입력하고 웹 애플리케이션 프로젝트를 실행하여 봅니다.

image

Memo 테이블의 로우 갯수를 출력하는 코드인데, 샘플 애플리케이션과 함께 배포된 DB에는 10개의 메모가 들어 있습니다.

따라서 10이 출력되면 정상입니다.

MemoList.aspx 페이지

메모들의 목록을 표시하는 페이지를 만듭시다.

프로젝트에 새 아이템을 추가하고 이름을 MemoList라고 합니다.

이 페이지가 하는 일은 다음과 같습니다.

  • 제목으로 검색된 메모 목록을 표시한다.
  • 메모를 클릭하면 해당 메모의 상세화면이 열린다.
  • 페이징을 지원한다.

여기서 약간의 통찰력을 발휘할 필요가 있습니다.

위 요구사항을 보고 필요한 비지니스 로직을 찾아내어, 프리젠테이션 코드와 비지니스 로직 코드를 분리하여야 합니다.

지금은 요구사항이 간단하니까 별다른 고민 없이 다음과 같은 비지니스 메서드가 필요함을 알게 될 것입니다.

image

페이지에서 GetBySubject 메서드가 필요함을 알게되었으니, MemoList 페이지의 작성은 잠시 멈추고 GetBySubject 메서드를 먼저 구현해 보도록 하겠습니다.

필드에서라면 비지니스 로직을 담당하는 개발자에게 의뢰를 하는 형태가 될 수도 있겠지요.

커스텀 비지니스 로직의 구현

여기서부터는 비지니스 로직 담당자의 입장에서 생각을 해봅시다.

GetBySubject란 메서드를 작성하도록 요청을 받았는데, 이 메서드가 하는 일은 ‘제목에 특정 검색어가 포함된 메모들의 목록을 반환하되 페이징을 지원한다’ 입니다.

작성을 해봅시다.

먼저 커스텀 비지니스 로직을 구현하기 위한 클래스를 만들어야 할 텐데, 메모 엔터티에 대한 비지니스 로직이니까 MemoBiz 라는 클래스가 필요할 것입니다.

그런데 사실 이 클래스는 이미 MP가 만들어 놓았습니다.

그렇다면 GetBySubject 메서드를 구현하기 위해 MP가 만들어 놓은 MemoBiz 클래스를 수정하면 될까요?

물론 안될 이유는 없지만, MP가 생성한 코드는 수동으로 고치지 않는 것이 좋습니다.

왜냐하면 나중에 다시 코드가 생성되면 수동으로 추가한 코드가 덮어씌여지기 때문입니다.

대신에 MemoBiz 클래스 파일을 하나 더 추가하고 이를 partial 클래스로 선언하는 것이 정석입니다.

사실 MP가 생성한 모든 클래스는 partial 클래스라서 이러한 방식으로 커스터마이징을 할 수 있습니다.

Memopad.Biz 클래스의 CustomBiz 폴더에 Memo 클래스를 추가합니다.

(물론 CustomBiz 폴더가 아닌 다른 곳에 추가하여도 상관없지만, MP가 추천하는 구조는 CustomBiz 폴더 입니다.)

그럼 프로젝트의 구성은 아래와 같겠네요.

image

추가된 MemoBiz의 코드를 아래와 같이 수정합니다.

image

partial 클래스로 선언하고 네임 스페이스를 MP가 생성한 MemoBiz와 동일하게 맞춰주었습니다.

이제 GetBySubject를 구현합니다.

image

길어 보이기는 하지만 실제 코드는 한 줄입니다.

MemoBiz의 부모인 EntityBiz에 정의된

image

를 다시 호출하고 있습니다.

사실 이 포스트에서 가장 중요한 부분이 여기 입니다.

‘제목에 특정 검색어가 포함된 메모들의 목록을 반환하되 페이징을 지원하는’ 비지니스 메서드를 만드는데, 단 한 줄의 코드만이 필요합니다.

SqlConnection 이나 SqlCommand 객체를 만들 필요도 없으며, DataSet이나 SqlDataReader 같은 클래스는 아예 등장하지도 않습니다.

참고로 [DataObjectMethod(DataObjectMethodType.Select)] 라는 특성은 ObjectDataSource에서 사용되는 특성인데, 이 메서드가 ObjectDataSource의 SelectMethod로 표시되어야 한다는 의미입니다.

이 포스트의 뒤에서 좀 더 자세한 설명을 하도록 하겠습니다.

ObjectDataSource의 구성

다시 MemoList.aspx 페이지로 돌아가서 작업을 계속하도록 하겠습니다.

도구상자에서 ObjectDataSource를 끌어와 페이지에 추가합니다.

추가된 ObjectDataSource의 이름을 odsMemo로 변경한 후 데이터 소스 구성 대화상자를 엽니다.

image

첫번째 단계는 비지니스 객체를 선택하는 것인데, 그림에서 보듯이 선택할 수 있는 객체가 세 가지 밖에 없습니다.

이는 Show only data components 체크박스가 켜져 있기 때문입니다. 즉 이 체크박스가 켜져 있으면 [DataObject] 속성이 붙은 클래스만 이 곳에 표시합니다.

클래스의 수가 수 백개만 넘어도 이 옵션을 켜지 않으면 해당 클래스를 찾기가 힘이 들 것입니다.

참고로 MP가 생성한 비지니스 객체에는 기본적으로 [DataObject] 특성이 붙어 있습니다.

MemoBiz를 선택하고 다음으로 넘어 갑니다.

image

이번에는 SELECT 메서드를 선택합니다.

비주얼 스튜디오는 리플렉션을 통해 SELECT 메서드로 사용할 수 있는 MemoBiz 클래스의 메서드의 목록을 추정하여 보여줍니다.

만일 비주얼 스튜디오의 추정을 통하지 않고 명식적으로 지정하고 싶다면 메서드에 [DataObjectMethod] 특성을 붙여주면 됩니다.

또한 [DataObjectMethod]의 매개변수를 지정함에 따라, 위 그림과 같이 여러 개의 후보 메서드 중에서 기본값으로 지정할 수도 있습니다.

여기서는 위에서 만든 GetBySubject를 선택하고 다음으로 넘어갑니다.

(UPDATE, INSERT,DELETE 메서드에는 이미 기본값이 지정되어 있긴 하지만, 사용하지 않을 메서드이므로 나중에 수동으로 삭제할 것입니다.)

image

마지막으로 GetBySubject의 매개변수를 설정하야 하는데, GetBySubject의 경우에는 특별한 설정이 필요없습니다.

text 매개변수의 경우에는 사실 TextBox 컨트롤에서 값을 읽어오는 것이 정석이겠으나, 여기서는 데모의 목적으로 코드에서 직접 설정하는 방법을 택할 것입니다.

또한 startRowIndex와 maximumRows 이 두 개의 매개변수는 페이징을 위한 것으로서, 나중에 추가할 DataPager 컨트롤이 제어할 값으로 개발자가 직접 제어할 필요가 없습니다.

따라서 그냥 마침을 눌러 ObjectDataSource의 구성을 끝마칩니다.

또한 ObjectDataSource의 InsertMethod, UpdateMethod, DeleteMethod 속성은 사용되지 않으니까 삭제합니다.

ObjectDataSource에 이벤트 추가

이제 ObjectDataSource의 매개변수인 text의 값을 설정하는 코드를 작성할 차례입니다.

text의 값을 설정하기에 가장 적절한 곳은 ObjectDataSource의 OnSelecting 이벤트일 것입니다.

ObjectDataSource의 OnSelecting 이벤트 핸들러를 추가합니다.

(그 전에 txtSearch 라는 TextBox를 페이지에 추가해 두시기 바랍니다.)

image

ObjectDataSource에 페이징 추가

이번에는 ObjectDataSource에 페이징을 추가해 봅시다.

ObjectDataSource에 페이징을 추가하기 위해서는 EnablePaging 속성을 true로 설정하는 것과 더불어 아래와 같이 세 개의 속성을 추가로 지정하여야 합니다.

  • SelectCountMethod
  • StartRowIndexParameterName
  • MaximumRowsParameterName

SelectCountMethod는 전체 로우의 갯수를 반환하는 메서드의 이름입니다.

현재 이런 일을 하는 메서드는 없으니까 새로 만들어야 합니다.

GetBySubject가 정의된 MemoBiz에 GetBySubjectCount 라는 메서드를 만들어 봅시다.

먼저 GetBySubjectCount의 시그니처에 대해서 살펴보면, 반환값은 당연히 int 형이면 되지만, 매개변수의 경우에는 특정한 룰이 있습니다.

ObjectDataSource의 SelectMethod에 지정된 메서드의 매개변수를 모두 포함하여야 하고, 추가로 마지막에 두 개의 int 형을 가져야 한다는 것인데, 이 규칙을 ObjectDataSource에 대입하면 GetBySubjectCount의 시그니처는 다음과 같게 됩니다.

public int GetBySubjectCount(string text, int startRowIndex, int maximumRows)

시그니처만 알아내면 실제 구현은 무척 간단합니다.

GetBySubject 메서드가 정의된 MemoBiz 클래스에 GetBySubjectCount 메서드를 정의합니다.

image

마찬가지로 단 한 줄의 코드로 구현이 가능합니다.

GetBySubjectCount 메서드를 구현했으니 ObjectDataSource의 SelectCountMethod 속성의 값을 GetBySubjectCount 라고 설정합니다.

StartRowIndexParameterName와 MaximumRowsParameterName 속성의 값은 각각 페이징 메서드에서 가져올 로우의 인덱스와 갯수를 지정하는 매개변수의 이름을 나타내는데, 기본값은 각각 startRowIndex와 maximumRows로 지정이 되어 있습니다.

위에서 구현한 GetBySubjectCount의 매개변수의 이름이 이 기본값과 이미 동일하게 설정되어 있으므로 이 두 속성은 지정하지 않아도 괜찮습니다.

여기까지 작업된 ObjectDataSource의 코드는 다음과 같습니다.

image

ListView 추가

메모의 목록을 표시하기 위해서 ListView 컨트롤을 사용하겠습니다.

MemoList.aspx 페이지에 ListView 컨트롤을 추가하고 아래와 같이 구성합니다.

image

ListView에 대한 설명은 이 포스트의 범위를 넘어 자세한 설명을 할 수는 없지만, ListView는 ASP.NET 3.5에서 가장 강력한 데이터 바인딩 컨트롤입니다.

적어도 MSDN에 있는 ListView의 설명 만은 꼭 익혀두시길 권장합니다.

DataPager의 추가

페이징을 사용하기 위해 DataPager 컨트롤을 추가합니다.

image

페이징을 시연하기 위해 PageSize를 3으로 지정하였습니다.

MemoList.aspx의 완성

여기까지 해서 MemoList.aspx 페이지가 완성되었습니다.

프로젝트를 실행하면 아래와 같은 화면을 볼 수 있습니다.

image

링크를 눌러 보면 검색과 페이징이 동작함을 확인할 수 있습니다.

MemoDetail.aspx의 ObjectDataSource

지금부터는 Midnight Peach 2.0 샘플 애플리케이션, 웹 애플리케이션의 두 번째 페이지인 MemoDetail.aspx를 만들어보도록 하겠습니다.

프로젝트에 MemoDetail.aspx를 추가하고 ObjectDataSource를 추가합니다.

ObjectDataSource를 추가하는 이유는 메모 엔터티의 상세 정보를 보여주기 위해 DetailsView 컨트롤의 사용할 것인데, 이 DetailsView의 데이터 소스로 ObjectDataSource를 사용하기 때문입니다.

먼저 ObjectDataSource를 구성한 후 DetailsView 컨트롤을 추가하도록 하겠습니다.

ObjectDataSource 구성 대화상자나 이용하거나 직접 타이핑하거나 하여 아래와 같이 ObjectDataSource를 구성합니다.

image

이번 경우에는 ObjectDataSource에 지정된 모든 메서드가 MP에서 이미 생성해 둔 것이므로 추가로 비지니스 메서드를 만들 필요가 없습니다.

바로 DetailsView 컨트롤로 넘어 갑시다.

DetailsView 컨트롤

MemoDetail.aspx 페이지에 DetailsView 컨트롤을 추가하고 아래와 같이 설정합니다.

image

대체로 이해하기 무난한 코드인데, 두 개의 이벤트 핸들러에 관해서는 좀 더 설명을 드려야 할 것 같습니다.

먼저 OnItemUpdating 이벤트의 이벤트 핸들러를 다음과 같이 구현합니다.

image

OnItemUpdating 이벤트는 물론 Memo 객체가 변경되기 전에 발생하는데, DetailsViewUpdateEventArgs의 NewValues에는 새로 업데이트 할 값이 저장되어 있습니다.

이때 Memo 객체의 경우에는 두 가지 문제가 발생합니다.

먼저 WrittenAt 속성은 DateTime 형인데, 새로 업데이트할 값으로 전달된 값은 string 형입니다. 따라서 이를 DateTime 형으로 형변환을 하여야 합니다.

또 Body 속성은 null을 허용하지 않으므로, 만일 null이 전달된다면 빈 문자열로 변환하여야 합니다.

마찬가지로 OnItemInserting 이벤트는 Memo 객체가 추가되기 전에 발생합니다.

역시 DetailsViewUpdateEventArgs의 Values에는 추가될 Memo 객체의 값이 넘어옵니다.

여기서 추가될 Memo 객체는 Memo의 기본 생성자로 생성되는데, 그렇다면 그 멤버 필드는 기본값으로 초기화가 됩니다.

즉, Memo 객체라면 WrittenAt은 DateTime형이니까 1년 1월 1일 자정이라는 값을 가지고 string 형인 Subject 등은 null 값을 가지게 됩니다.

하지만 Memo 객체는 DB 스키마와 DBML 파일의 정의에 의해 이러한 값을 지정할 수 없습니다.

따라서 아래와 같이 새로 생성된 Memo 객체의 값을 적당한 값으로 초기화하는 코드가 필요합니다.

 

이렇게 해서 메모패드 웹 애플리케이션을 만들어보았습니다.

: