Value of Life

데이터베이스 프로그래밍 본문

IT/데이터 베이스 프로그래밍

데이터베이스 프로그래밍

앵글메이커 2008. 7. 25. 09:26
반응형
데이터베이스 프로그래밍

 

데이터베이스 애플리케이션

            DB시스템의 구성     관계형 DB     MFC DB클래스

ODBC 데이터베이스 사용하기

            데이터 읽기-리스트 컨트롤                        리코드셋 클래스 사용

레코드뷰로 데이터베이스 보기

            레코드와 레코드뷰의 연결, 날짜 처리

레코드의 추가, 삭제, 변경                  데이터베이스 검색 정렬

데이터베이스에 이미지 저장하기    DAO비디오 관리 프로그램

 

16-1. 데이터베이스 애플리케이션

 . 데이터베이스 시스템의 구성

사용자

=>

인터페이스

=>

DBMS(관리)

=>

·DB애플리케이션

(추가,수정,삭제,검색)

·ODBC(드라이버)

  -네트워크 지원

·DAO-단독

·저장 구조 정의

·효율적인 저장

·데이터 추출

·오류저장 방지

·동시 접근

 

 

DB관리 언어

 

 

DML(SQL)

 

 

오라클, 인포믹스

 

 

1. 데이터베이스

  데이터의 저장: 데이터베이스는 유용한 데이터를 모아둔

  데이터의 검색: 사용자가 원하는 조건에 의해 검색 가능

  데이터의 갱신: 변화에 대처하여 현재상황을 올바로 저장

2. DBMS

  데이터베이스를 관리 하는데 필요한 모든 일을 수행하는 시스템

  데이터베이스 관리 시스템의 역할:

   -데이터 저장 구조 정의 효율적으로 저장

   -사용자가 원하는 데이터를 추출

   -잘못된 데이터가 저장되는 것을 방지

   -동시에 여러 사람이 접근하여 사용 가능

3. 데이터베이스 애플리케이션

  데이터를 추가, 수정, 삭제, 검색하기 위한 인터페이스를 제공하는 프로그램

4. 데이터베이스 관리 언어

  DBMS 명령을 내릴 사용하는 언어

  SQL(Structured Query Language): 가장 널리 쓰이는 언어

5. ODBC DAO

  ODBC: 데이터베이스 애플리케이션과 DBMS 연결시키는 표준적인 인터페이스를 제공, 네트워크를 지원하며 다중 사용자 인터페이스에 접속 가능

  DAO: 단독으로 데이터베이스 사용할 효율적

 . 관계형 데이터베이스

1. 데이터의 저장

  레코드: 관련된 것끼리 묶어서 저장하는 데이터의 묶음

    : 레코드를 구성하는 항목

2. 인덱스

  실제 레코드를 가리키는 포인터를 가지고 있음

3. 데이터베이스의 설계

      

·학생 테이블

·이름, 학번, 학과

·강좌 테이블

·과목명, 담당교수, 강의실, 강의시간

      

·수강 테이블

·학번, 과목명, 학점

관계의 종류

·일

·학생 학번

·다

·학생 강좌

·다

·모든 학생 1명의 지도 교수

  어떤 데이터를 어떻게 저장할 것인가?, 중복 방지, 추가 삭제 검색 용이

4. 개체-관계 모델

  개체(Entity): 다른 것들과 구별이 가능한 데이터 저장 단위

            속성(attribute): 개체 자신의 특성

  관계(Relationship): 학생과 강좌 사이에 수강이라는 관계

5. 관계형 데이터베이스: 개체-관계 모델을 테이블의 집합체로 표현

  개체 테이블: 학생(개체) 테이블- 이름, 학번, 학과의 필드(속성)

  관계 테이블: 개체들의 속성 중복이 되지 않는 속성들 + 관계자체가 갖는 속성

             수강(관계 테이블)=학번(학생 테이블)+과목(강좌 테이블)+학점(관계 자체)

6. 관계의 종류

  개체의 속성과 개체간의 관계: 유용한 정보를 잃지 않는 범위 내에서 정보의 중복 저장을 최소화

  일의 관계: 학생과 학번-학생의 속성으로 간주

  다의 관계: 학생과 강좌-각각 독립된 테이블

  일의 관계: 모든 학생이 명의 지도교수를 가질 -학생 테이블에 교수의 속성 포함

7. 관계형 데이터베이스에서 데이터 추출 방법

  SELECTION: 단위, 주어진 조건을 만족하는 행들을 추려서 새로운 테이블을 만듦

  PROJECTION: 단위, 테이블에 저장되어 있는 속성 일부를 추려서 새로운 테이블 만듦

  집합연산

  JOIN: 여러 테이블에 나뉘어 저장되어 있는 내용을 합침

 

 . MFC의 데이터베이스 클래스

 

 

데이터

베이스

 ODBC: CDatabase-ExcuteSQL 이용 SQL문장을 DBMS 전달

 DAO : CDaoDatabase-Excute //

·데이터베이스와의 연결 관리, Open, Close

리코드셋

ODBC: CRecordset

DAO : CDaoRecordset

·레코드들의 집합, 데이터의 추가, 삭제, 수정, 검색, 정렬 등에 관련된 기능

레코드뷰

ODBC: CRecordView

DAO : CDaoRecordView

·레코드셋의 데이터를 레코드 단위로 화면에 보여주는 기능

에러처리

ODBC: CDBException

DAO : CDaoException

 

DAO

CDaoTableDef

·필드 추가, 삭제, 인덱스 추가,삭제

CDaoQueryDef

·리코드셋 생성

CDaoWorkspace

·보안,  트랜잭션 처리

16-2. ODBC 데이터베이스 사용하기

1. 구현 기능: 저장된 DB 리스트 컨트롤에 표시

2. 데이터 소스 만들기

  MS 액세스 사용: 필드 생성(이름, 생년월일, 전화번호, 호출번호, 성별, 주소)=>namecard테이블

3. ODBC데이터 원본 관리자에 데이터 소스 등록

  제어판의 32비트 ODBC선택->드라이버 선택->데이터 원본이름 지정

4. 프로그램 작성

  프로그램 뼈대: 다이얼로그 박스 기반

   - ODBC관련 클래스 사용할 StdAfx.h #include <afxdb.h>

  CRecordSet파생클래스 추가: CNamecardSet, ODBC 테이블 선택

 리코드셋

 클래스

·데이터 소스 설정

  CString CNamecardSet::GetDefaultConnect() return _T("ODBC;DSN=namecard");

·테이블 설정

  CString CNamecardSet::GetDefaultSQL()     return _T("[namecard]");

·생성된 멤버변수

  class CNamecardSet : public CRecordset

  // Field/Param Data

            //AFX_FIELD(CNamecardSet, CRecordset)

            long    m_nID;       CString   m_strName;  CString   m_strPhone;

            CString m_strPager;  BOOL    m_bSex;                CString   m_strAddress;

            CTime  m_dateBirth;

            //AFX_FIELD

  ;

·데이터 소스와 레코드셋의 연결

  void CNamecardSet::DoFieldExchange(CFieldExchange* pFX)

            //AFX_FIELD_MAP(CNamecardSet)

            pFX->SetFieldType(CFieldExchange::outputColumn);

            RFX_Long(pFX, _T("[nID]"), m_nID);

            RFX_Text(pFX, _T("[strName]"), m_strName);

                        //

            //AFX_FIELD_MAP

 

·m_nFields멤버변수

  CNamecardSet::CNamecardSet(CDatabase* pdb)

            : CRecordset(pdb)

            //AFX_FIELD_INIT(CNamecardSet)

            m_nID = 0;                  m_strName = _T("");

                        //

            m_nFields = 7;

            //AFX_FIELD_INIT

            m_nDefaultType = snapshot;

 

리코드셋

클래스

사용

  #include "NamecardSet.h"

  class CSimpleViewerDlg : public CDialog   CNamecardSet m_Set; ;

  BOOL CSimpleViewerDlg::OnInitDialog()  m_Set.Open();       SetData(); return TRUE;

기타 작업

  리스트 컨트롤 초기화, 비트맵 생성, InsertColumn으로 칼럼 추가

 레코드값 읽어오기

   void CSimpleViewerDlg::SetData()

            LV_ITEM lvitem;         CString str;       int i=0;

           

            if(!m_Set.IsBOF()) m_Set.MoveFirst();                     // 첫번째 레코드로 이동

            lvitem.mask = LVIF_TEXT | LVIF_IMAGE;

            lvitem.iSubItem = 0;

 

            while(!m_Set.IsEOF())                                               // 마지막 레코드까지…

              lvitem.iItem = i++;

 

              lvitem.pszText = (LPSTR)(LPCTSTR)m_Set.m_strName;                  // 이름 설정

              lvitem.iImage = m_Set.m_bSex;

 

              m_ctrlList.InsertItem(&lvitem);                                    // 새로운 등록

                       

              str = m_Set.m_dateBirth.Format("%y.%m.%d");         // 컬럼의 텍스트 설정

              m_ctrlList.SetItemText(lvitem.iItem, 1, (LPCTSTR)str);

              m_ctrlList.SetItemText(lvitem.iItem, 2, (LPCTSTR)m_Set.m_strPhone);

              m_ctrlList.SetItemText(lvitem.iItem, 3, (LPCTSTR)m_Set.m_strPager);

              m_ctrlList.SetItemText(lvitem.iItem, 4, (LPCTSTR)m_Set.m_strAddress);

 

              m_Set.MoveNext();                         // 다음 레코드로 이동

           

  

 

 리스트 컨트롤 초기화/ 비트맵 생성/ 이미지 등록

   BOOL CSimpleViewerDlg::OnInitDialog()

                        //

            // 작은 아이콘 설정

            m_ImageList.Create(IDB_SMALL, 16, 2, RGB(255, 255, 255));

            m_ctrlList.SetImageList(&m_ImageList, LVSIL_SMALL);       // 연결

            InsertColumn();

 

            m_Set.Open();

            SetData();

           

            return TRUE; 

  

 컨트롤에 칼럼 추가

   void CSimpleViewerDlg::InsertColumn()

  

            CRect rect;

            m_ctrlList.GetClientRect(&rect);

 

           

            LV_COLUMN lvcolumn;                  // 컬럼에 대한 정보를 저장하는 구조체

 

            // 설정할 항목들을 명시함

            lvcolumn.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;

            lvcolumn.fmt = LVCFMT_LEFT;         // 컬럼 헤더를 왼쪽에 출력하도록

 

            for(int i = 0 ; i < 5 ; i++ )

                        lvcolumn.iSubItem = i;

                        switch(i)

                       

                        case 0:  lvcolumn.cx = 80;                     // 첫번째 컬럼 정보 설정

                                    lvcolumn.pszText = "이름";

                                    break;

                        case 1:  lvcolumn.cx = 80;                     // 두번째 컬럼 정보 설정

                                    lvcolumn.pszText = "생년월일";

                                    break;

                        case 2:  lvcolumn.cx = 80;                     // 세번째 컬럼 정보 설정

                                    lvcolumn.pszText = "전화번호";

                                    break;

                        case 3:  lvcolumn.cx = 120;                   // 네번째 컬럼 정보 설정

                                    lvcolumn.pszText = "호출번호";

                                    break;

                        case 4:  lvcolumn.cx = rect.Width()-360;           // 네번째 컬럼 정보 설정

                                    lvcolumn.pszText = "주소";

                                    break;

                       

                        m_ctrlList.InsertColumn(i, &lvcolumn); // 컬럼 추가

           

  

 

 

16-3. 레코드뷰로 데이터베이스보기

1. 구현기능: CRecordView 이용한 레코드 브라우징

 

2. 프로그램 뼈대: 레코드뷰 지원 옵숀 선택

  SDI, Database view without file support, Data Source선택

 

3. 데이터 소스의 레코드와 레코드뷰 연결

  레코드를 보여줄 컨트롤 배치

  레코드셋의 멤버변수와 컨트롤 연결

 

4. 데이터 소스의 레코드와 레코드뷰의 연결 원리

  레코드셋과 레코드뷰의 관계

  -레코드셋은 도큐먼트의 멤버변수 선언

   class CRecDoc : public CDocument

            CNamecardSet m_namecardSet;   ;

  -레코드뷰에는 레코드셋의 포인터가 멤버변수 선언

   class CRecView : public CRecordView

            //AFX_DATA(CRecView)

            enum  IDD = IDD_RECORDVIEWER_FORM ;

            CNamecardSet* m_pSet;

            //AFX_DATA

  

  -레코드뷰의 멤버변수인 레코드셋 포인터는 도큐먼트의 멤버변수인 레코드셋 가리킴

   void CRecView::OnInitialUpdate()

            m_pSet = &GetDocument()->m_namecardSet;

            CRecordView::OnInitialUpdate();

  

 

  -레코드셋의 인스턴스는 도큐먼트에 저장하되 레코드뷰에서 이를 참조 가능

   CRecordset* CRecView::OnGetRecordset() 

            return m_pSet;  

 

 레코드뷰의 컨트롤과 레코드셋의 연결

   void CRecView::DoDataExchange(CDataExchange* pDX)

  

            CRecordView::DoDataExchange(pDX);

            //AFX_DATA_MAP(CRecView)

            DDX_FieldText(pDX, IDC_EDIT1, m_pSet->m_strName, m_pSet);

            DDX_FieldCheck(pDX, IDC_CHECK1, m_pSet->m_bSex, m_pSet);

            DDX_FieldText(pDX, IDC_EDIT3, m_pSet->m_strPhone, m_pSet);

            DDX_FieldText(pDX, IDC_EDIT4, m_pSet->m_strPager, m_pSet);

            DDX_FieldText(pDX, IDC_EDIT5, m_pSet->m_strAddress, m_pSet);

            //AFX_DATA_MAP

           

            if(pDX->m_bSaveAndValidate)                                   // 쓰기 모드일 경우...

               DDX_Text(pDX, IDC_EDIT2, m_date); //입력된 내용을 COleDateTime 변수로 받아

                                                                         //m_pSet->m_dateBirth 설정

                m_pSet->m_dateBirth = CTime(m_date.GetYear(), m_date.GetMonth(), m_date.GetDay(),

                                    m_date.GetHour(), m_date.GetMinute(), m_date.GetSecond());

           

           

            else                                                                  // 읽기 모드일 경우

                DDX_FieldText(pDX, IDC_EDIT2, m_pSet->m_dateBirth.Format("%y/%m/%d"), m_pSet);

  

5. 날짜처리

  DDX_FieldText함수의 처리 범위

  -CTime클래스를 CString형으로 변환하여 처리

6. 레코드 스크롤

  CRecordView OnMove함수에서 자동으로 처리

7. 프레임 윈도우 처리

  프레임 윈도우의 크기를 뷰의 크기에 맞추어 조절

   void CRecView::OnInitialUpdate()

            GetParentFrame()->RecalcLayout();

            ResizeParentToFit();

  

  프레임 윈도우의 타이틀

  -리소스에서 문자열 테이블을 열고 IDR_MAINFRAME 으로 구분된 7개의 문자열중 번째 항목에 제목을 추가

  -제목없음의 문자열 제거

   BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)

            cs.style ^= FWS_ADDTOTITLE;

            return CFrameWnd::PreCreateWindow(cs);

  

 

16-4. 레코드의 추가, 삭제, 변경

1. 구현 기능: 새로운 레코드를 추가, 삭제,  툴바에 새레코드와 레코드 삭제 버튼 추가

2. 레코드 삭제

  툴바에서 레코드 삭제 버튼->CRecordset클래스의 Delete, MoveNext, MoveNext

   void CRecView::OnRecordDelete()

  

            TRY

                        m_pSet->Delete();                             // 레코드 삭제

            CATCH(CDBException, e)

                        AfxMessageBox(e->m_strError);

                        return;

           

            END_CATCH

 

            m_pSet->MoveNext();                                               // 삭제된 다음 레코드로 이동

 

            if (m_pSet->IsEOF())                                      // 파일의 끝이면 마지막 레코드로 이동

                        m_pSet->MoveLast();

 

            if (m_pSet->IsBOF())                                      // 레코드가 하나도 없으면 빈칸 출력

                        m_pSet->SetFieldNull(NULL);

            UpdateData(FALSE);

  

3. 레코드 추가

   void CRecView::OnRecordNew()

            if (m_bAddMode)                    // 이미 추가 모드이면 이전의 추가 작업을 마무리

               OnMove(ID_RECORD_FIRST);

 

            m_pSet->AddNew();      // 새로운 레코드 추가 (나머지 작업은 OnMove에서 수행)

            m_bAddMode = TRUE;

            UpdateData(FALSE);

  

 

   BOOL CRecView::OnMove(UINT nIDMoveCommand) //레코드가 스크롤 호출

            if (m_bAddMode)                                // 새로운 레코드를 추가하는 모드이면...

                        if (!UpdateData())                     // 컨트롤에 입력된 내용을 멤버 변수에 저장

                                    return FALSE;

                        TRY

                                                           

                                    m_pSet->Update();     // 레코드 갱신

                       

                        CATCH(CDBException, e)

                       

                                    AfxMessageBox(e->m_strError);

                                    return FALSE;

                       

                        END_CATCH

 

                        m_pSet->Requery();              // 새로 추가된 레코드를 반영하기 위해...

                        UpdateData(FALSE);

                        m_bAddMode = FALSE;

                        return TRUE;

           

            else

                                                                        // 추가 모드가 아니면 기본 동작을 수행

                        return CRecordView::OnMove(nIDMoveCommand);

           

  

3. 기존 레코드의 내용 변경

            m_pSet->Edit();

            m_pSet->m_strName="홍길동

            m_pSet->Update();

 

16-5. 데이터베이스 검색 정렬

1. 구현 기능: 검색, 정렬

2. 데이터 검색: CRecordset m_strFilter멤버변수 사용

            m_pSet->m_strFilter = "strName = '홍길동;

            m_pSet->Requery();

            //(SELECT*FROM namecard WHERE strName = '홍길동)

 데이터 타입에 따른 표현

  문자열: 꺢ケ役, 숫자: 20,  날짜: #77/5/3#, 공백문자 포함: 변수를[] 묶음

 조건의 결합

  AND 또는 OR 등과 같은 논리 연산자로 40개까지

 비슷한 검색

  - LIKE키워드와 와일드카드 문자: LIKE '%%, -임의갯수, []지정된 범위내,[^]지정된 범위내의 문자제외, NOT

3. 데이터 정렬: m_strSort                           //SQL ORDER BY

            m_pSet->m_strSort = "strName;

            m_pSet->Requery();

 내림차순, 오름차순:

            m_pSet->m_strSort = "strName DESC;,            //"strName ASC

            m_pSet->Requery();

 정렬조건의 결합

            m_pSet->m_strSort = "strName DESC, nAge ASC

            m_pSet->Requery();

4. 검색과 정렬의 구현

   void CQueryDlg::OnOK()                      //정렬 질의 선택

  

            int nSel;

 

            char *strField[] = "strName", "dateBirth", "bSex", "strPhone", "strPager", "strAddress";

            UpdateData();

 

            nSel = m_ctrlCombo1.GetCurSel();

            if(nSel < 0)       m_strSort.Empty();

            else                              m_strSort = strField[nSel];

 

            nSel = m_ctrlCombo2.GetCurSel();

            if(m_strQuery.IsEmpty() || nSel < 0)

                        m_strFilter.Empty();

            else

           

                        if(nSel == 1)

                                    m_strFilter.Format("%s = #%s#", strField[nSel], m_strQuery);

                        else if(nSel == 2)

                                    m_strFilter.Format("%s = %s", strField[nSel], m_strQuery);

                        else

                                    m_strFilter.Format("%s = '%s'", strField[nSel], m_strQuery);

           

            CDialog::OnOK();

  

   void CRecView::OnQuery()                              //다이얼로그 박스 출력

  

            CQueryDlg dlg;

            if(dlg.DoModal() == IDOK)

           

                        m_pSet->m_strSort = dlg.m_strSort;                // 정렬

                        m_pSet->m_strFilter = dlg.m_strFilter;             // 질의

 

                        m_pSet->Requery();

                        UpdateData(FALSE);

           

  

   void CRecView::OnSql()                       //질의 문장를 직접 입력

  

            CSQLDlg dlg;

            if(dlg.DoModal() == IDOK)

           

                        m_pSet->m_strFilter = dlg.m_strFilter;

                        m_pSet->Requery();

           

  

 

16-6. 데이터베이스에 이미지 저장하기

1. 구현기능: 이미지 데이터를 데이터베이스에 저장

2. CImage 클래스 사용

3. 이미지 저장을 위한 필드 생성

 데이터 소스에 이미지 저장 필드 추가: 액세스-OLE개체 형식

 레코드셋의 멤버변수 추가: ClassWizard에서 Update Columns버튼 사용

   class CNamecardSet : public CRecordset

  

            CLongBinary  m_lbImage;

   ;

   void CNamecardSet::DoFieldExchange(CFieldExchange* pFX)

  

            //AFX_FIELD_MAP(CNamecardSet)

            RFX_LongBinary(pFX, _T("[image]"), m_lbImage);

            //AFX_FIELD_MAP

  

4. 이미지 저장

 CImage클래스의 인스턴스 저장

   class CRecView : public CRecordView

  

            CImage m_Image;

   ;

 이미지 읽어오기

   void CRecView::OnLoadpicture()

  

            char szFilter[] = "그림 파일(*.BMP)|*.bmp|모든 파일(*.*)|*.*||";

 

            CFileDialog fileDlg(TRUE, NULL, NULL, OFN_HIDEREADONLY, szFilter);

            if(IDOK == fileDlg.DoModal())

           

                        if(m_Image.Load(fileDlg.GetPathName()))

                       

                                    // 레코드 추가 모드가 아니면 편집 모드로 만듦

                                    if (!m_bAddMode) m_pSet->Edit();

                                   

                                    // 이미지가 저장된 메모리 핸들을 저장하기 위해 설정

                                    m_pSet->m_lbImage.m_hData = CopyHandle(m_Image.GetHandle());

                     m_pSet->m_lbImage.m_dwDataLength=GlobalSize(m_pSet->m_lbImage.m_hData);

 

                                    // 데이터를 저장하도록

                                    m_pSet->SetFieldDirty(&m_pSet->m_lbImage);    //필드내용변경

                                    m_pSet->SetFieldNull(&m_pSet->m_lbImage, FALSE);

 

                                    // 레코드 추가 모드가 아니면 데이터 저장

                                    if (!m_bAddMode) m_pSet->Update();

 

                                    DrawPicture();              // 이미지를 화면에 그림

                       

           

  

5. 이미지를 화면에 그리기

   void CRecView::DrawPicture()

  

            CClientDC dc(this);

            CRect rcDest;

            m_ctrlPicture.GetWindowRect(&rcDest);

            ScreenToClient(&rcDest);

 

            if ( !m_Image.IsDataNull() )

           

                        CRect rcDIB;                                       // 이미지 데이터가 있는 경우

                        rcDIB.top = rcDIB.left = 0;

                        rcDIB.right = m_Image.GetWidth();

                        rcDIB.bottom = m_Image.GetHeight();

                       

                        m_Image.Draw(dc.m_hDC, &rcDIB, &rcDest);

           

            else

                        dc.Rectangle(rcDest);                           // 이미지 데이터가 없는 경우

  

6.스크롤

   BOOL CRecView::OnMove(UINT nIDMoveCommand)

                                    //

            if(!m_pSet->IsFieldNull(&m_pSet->m_lbImage))         // 이미지 데이터가 입력되어 있으면…

                        m_Image.Free();                                               // 기존의 이미지를 버리고,

                        m_Image.SetHandle(                            // 데이터베이스에 저장된 이미지를 설정

                                    (HDIB)CopyHandle(m_pSet->m_lbImage.m_hData));

                        m_Image.InitDIB();

           

            else

                        m_Image.Free();

            DrawPicture();

            return result;

 

 

16-7.DAO비디오 샵관리 프로그램

1. 구현기능:

 ①비디오 테이프 대여, 반납: 고객 이름,번호로 검색,  고객별로 대여한 비디오 목록 관리

 ②테이프 관리: 소장 테이프 정보 열람, 추가, 삭제

 ③고객관리:

2. 데이터 소스 만들기

 데이터베이스 설계

  -개체: 고객과 비디오,  -관계: 대여,  - 다의 관계이므로 각각 독립된 테이블에 저장

 테이블 생성

              : 고객번호, 이름, 전화번호, 주소, 주민등록번호

            비디오: 테이프번호, 영화제목, 주연배우, 장르, 연소자 관람등급, 출시사

              : 대여 고객번호, 테이프번호, 대여일

3, 프로그램 뼈대

   SDI, Database view without file support, DAO선택, mdb파일명 설정

   테이블마다 CDaoRecordView CDaoRecordset파생클래스를 만듦

4. 다중 레코드셋을 사용할 데이터베이스와 연결

 레코드셋 클래스의 인스턴스 선언

 

   #include "RentSet.h"

   #include "CustomerSet.h"

   #include "TapeSet.h"

 

   class CVideoDoc : public CDocument

  

   public:

            CRentSet m_rentSet;

            CCustomerSet m_customerSet;

            CTapeSet m_tapeSet;

   ;

 CDaoDatabase

   class CVideoDoc : public CDocument

  

   protected:

            CDaoDatabase m_database;    //다중 레코드셋 사용시 명시적으로 생성

   ;

 데이터베이스 연결

   CDaoDatabase* CVideoDoc::GetDatabase()

  

            if (!m_database.IsOpen())

           

                        try

                       

                                    m_database.Open(_T("video.mdb"));    // 데이터베이스 파일 열기

                       

                        catch (CDaoException* e)

                       

                                    // Assume failure is becauase we couldn't find the file

                                    e->Delete();

                       

           

            if (!m_database.IsOpen())                                             // 만약 파일이 없거나, 열리지 않으면…

           

                        // 파일 열기 다이얼로그 박스 출력

                                    CFileDialog dlgFile(TRUE, _T(".mdb"), NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,

                                    _T("데이터베이스 파일(*.mdb)|*.mdb|모든 파일(*.*)|*.*||"));

                        if (dlgFile.DoModal() == IDCANCEL)

                                    return NULL;

                        try

                       

                             m_database.Open(dlgFile.GetFileName()); // 사용자가 선택한 새로운 파일 열기

                       

                        catch (CDaoException* e)

                       

                                    // Tell them the reason it failed to open

                                    AfxMessageBox(e->m_pErrorInfo->m_strDescription);

                                    e->Delete();

                                    return NULL;

                       

           

            if (!m_database.IsOpen())

                        return NULL;

            return &m_database;                // 데이터베이스 반환

  

 레코드뷰와 레코드셋 연결: 각각의 뷰가 레코드셋의 포인터를 갖도록

   class CCustomerView : public CDaoRecordView

  

   public:

            //AFX_DATA(CCustomerView)

            enum  IDD = IDD_CUSTOMER_FORM ;

            CCustomerSet* m_pSet;

            //AFX_DATA

   ;

   void CRentView::OnInitialUpdate()    // 뷰에서 포인터 초기화

  

            BeginWaitCursor();

 

            CVideoDoc* pDoc = (CVideoDoc*)GetDocument();

            CDaoDatabase* pDatabase = pDoc->GetDatabase();

            if (!pDatabase->IsOpen())

                        return;

            m_pSet = &pDoc->m_rentSet;

            m_pSet->m_pDatabase = pDatabase;

 

            CDaoRecordView::OnInitialUpdate();

 

            GetParentFrame()->RecalcLayout();

            ResizeParentToFit();

           

            InsertColumn();                                                // 리스트 컨트롤 초기화

           

            EndWaitCursor();

  

5. 뷰의 전환

 기본 설정: CVideoApp클래스의 InitInstance함수의 도큐먼트와 뷰를 등록

  전환기능 작성

   void CMainFrame::SwitchToForm(int nForm)

  

            CView* pOldActiveView = GetActiveView();   // 현재 화면에 출력되어 있는 뷰의 포인터

            CView* pNewActiveView = (CView*)GetDlgItem(nForm);     // 새로 출력하려는 뷰의 포인터

 

            if (pNewActiveView == NULL)           // 새로 출력하는 뷰가 아직 만들어지지 않은 상태이면

           

                        if (nForm == IDD_RENT_FORM)                  // 뷰를 새로 생성

                                    pNewActiveView = (CView*)new CRentView;

                        else if (nForm == IDD_CUSTOMER_FORM)

                                    pNewActiveView = (CView*)new CCustomerView;

                        else

                                    pNewActiveView = (CView*)new CTapeView;

 

                        CCreateContext context;                                  // 도큐먼트와 뷰를 연결시켜

                        context.m_pCurrentDoc = pOldActiveView->GetDocument();

                                                            pNewActiveView->Create(NULL, NULL, 0L, CFrameWnd::rectDefault, this, nForm, &context);

 

                                                            // 초기화를 위해 OnInitialUpdate 함수 호출

                        pNewActiveView->OnInitialUpdate();

           

 

            SetActiveView(pNewActiveView);                   // 새로운 뷰를 활성화시키고, 이전 뷰를 감춤

            pNewActiveView->ShowWindow(SW_SHOW);

            pOldActiveView->ShowWindow(SW_HIDE);

           

                                    // 이전 뷰를 다음에 화면에 출력시키기 위하여 ID 기억해

            UINT nID;

            if(pOldActiveView->GetRuntimeClass() == RUNTIME_CLASS(CRentView))           

                        nID = IDD_RENT_FORM;

            else if(pOldActiveView->GetRuntimeClass() == RUNTIME_CLASS(CCustomerView))

                        nID = IDD_CUSTOMER_FORM;

            else

                        nID = IDD_TAPE_FORM;

 

            pOldActiveView->SetDlgCtrlID(nID);

            pNewActiveView->SetDlgCtrlID(AFX_IDW_PANE_FIRST);

            RecalcLayout();

  

  전환을 위한 메뉴 작성

  전환 작업: 메뉴 선택시

   void CMainFrame::OnRent()

  

            if (GetActiveView()->IsKindOf(RUNTIME_CLASS(CRentView)))

                        return; // 이미 활성화 상태이면 그냥 리턴

            SwitchToForm(IDD_RENT_FORM);

  

 현재 활성화된 표시

   void CMainFrame::OnUpdateRent(CCmdUI* pCmdUI)

  

            pCmdUI->SetCheck(GetActiveView()->IsKindOf(RUNTIME_CLASS(CRentView)));

  

6. 고객 관리 기능, 소장 테이프 관리 기능: 추가, 수정, 삭제

7. 대여 관리 기능

 대여 관리의 동작:

  - 고객찾기 버튼을 누르면 고객이름, 전화번호, 고객번호 사용

  - 고객이 대여한 테이프 정보 출력, 대여 반납 작업

 고객 찾기

   void CRentView::OnSearch()

  

            CCustomerSearchDlg dlg;

            if(dlg.DoModal() != IDOK) return;

 

            CVideoDoc* pDoc = (CVideoDoc*)GetDocument();

            CCustomerSet customerSet(pDoc->GetDatabase());

 

            customerSet.m_strFilter = dlg.m_strFilter;

            customerSet.Open();

 

            if(customerSet.IsEOF() && customerSet.IsBOF())

           

                        AfxMessageBox("그런 고객은 없습니다.");

                        return;

           

 

            m_nCurrentCustomerID = customerSet.m_nCustomerID;

            m_strCustomerID.Format("%d", m_nCurrentCustomerID);

            m_strName = customerSet.m_strName;

            m_strPhone = customerSet.m_strPhone;

            m_strAddress = customerSet.m_strAddress;

            m_strRegidentID = customerSet.m_strRegidentID;

            UpdateData(FALSE);

 

            m_pSet->m_strFilter.Format("Rent.nCustomerID = %d", customerSet.m_nCustomerID);

            m_pSet->Requery();

            UpdateList();

  

 JOIN연산으로 고객이 대여한 테이프 정보 얻기

  -INNERJOIN: 일치하는 행만

  -LEFTJOIN: 대여 테이블 전체를 포함하고 테이프 테이블에서 일치하는

  -RIGHTJOIN: 테이프 테이블 전체를 포함하고 대여 테이블에서 일치하는

 

 

 레코드셋에 JOIN 연산 적용

   CString CRentSet::GetDefaultSQL()

  

                                return _T("SELECT Rent.dateRent, Rent.nCustomerID, Rent.nTapeID, Tape.strTitle FROM Rent LEFT JOIN Tape ON Rent.nTapeID = Tape.nTapeID");

  

 고객이 대여한 테이프 목록 표시하기

            m_pSet->m_strFilter.Format("Rent.nCustomerID = %d", customerSet.m_nCustomerID);

            m_pSet->Requery();

            UpdateList();

  -리스트 컨트롤에 출력

   void CRentView::UpdateList()

  

            CString str;

            LV_ITEM lvitem;

            lvitem.iItem = 0;

            lvitem.mask = LVIF_TEXT;

 

            m_ctrlList.DeleteAllItems();

            if(!m_pSet->IsBOF()) m_pSet->MoveFirst();

 

            while(!m_pSet->IsEOF())

           

                        lvitem.iSubItem = 0;

                        str.Format("%d", m_pSet->m_nTapeID);

                        lvitem.pszText = (LPSTR)(LPCTSTR)str;

 

                        m_ctrlList.InsertItem(&lvitem);              // 새로운 등록

 

                                                                                    // 컬럼의 텍스트 설정

                        m_ctrlList.SetItemText(lvitem.iItem, 1, m_pSet->m_strTitle);

                        str = m_pSet->m_dateRent.Format("%y/%m/%d, %H:%M");

                        m_ctrlList.SetItemText(lvitem.iItem, 2, str);

 

                        lvitem.iItem++;

                        m_pSet->MoveNext();

           

  

 새로운 테이프 대여

   void CRentView::OnRecordNew()

  

            CRentDlg dlg;

            if(dlg.DoModal())        

           

                        CVideoDoc* pDoc = (CVideoDoc*)GetDocument();

                        m_pSet->AddNew();

                       

                        m_pSet->m_nCustomerID = m_nCurrentCustomerID;

                        m_pSet->m_nTapeID = dlg.m_nTapeID;

                        m_pSet->m_dateRent = COleDateTime::GetCurrentTime();

                       

                        m_pSet->Update();

                        m_pSet->Requery();

                        UpdateList();

           

  

 테이프 반납

   void CRentView::OnRecordDelete()

            LV_ITEM lvitem;

            int count = m_ctrlList.GetItemCount();

            int i;

            lvitem.mask = LVIF_STATE;

            if(!m_pSet->IsBOF()) m_pSet->MoveFirst();

 

            for(i=count-1 ; i>=0 ; I--)                     // 모든 항목을 조사하여

           

                        lvitem.iItem = i;

                        if(m_ctrlList.GetItemState(i, LVIS_SELECTED) != 0)

                       

                                    m_ctrlList.DeleteItem(i);           // 선택된 항목을 삭제

                                    m_pSet->Delete();

                       

                        m_pSet->MoveNext();

반응형

'IT > 데이터 베이스 프로그래밍' 카테고리의 다른 글

ODBC와 DAO(MFC)  (2) 2008.07.17