티스토리 뷰

프로그래밍/MFC

MFC ODBC2

에어버스 2016. 7. 23. 11:39

ODBC에 액세스 DB 추가 방법

1. 제어파에서 관리도구를 실행하면 아래 창이 뜨고 이떄 ODBC 데이터 원본(64비트) 를 선택한다.
(32비트로 선택하면 추가 안됨)

2. 사용자 DSN 탭이 선택된 상태에서 추가 버튼을 누른다.

3. Microsoft Access Driver 선택

4. 데이터 원본 이름에 student 라 입력하고 선택 버튼을 누른다.

5. 액세스 DB파일을 선택해주고 확인 버튼을 누른다.

6. 최종적으로 사용자 DSN에 student 가 추가된것을 확인할 수 있다.

이대로 실행하면 아래 창을 보이면서 에러 난다.

할수없이 ODBC 대신 DB파일을 직접 지정해주는 코드로 수정했다. (accdb 파일은 여기서도 동일 증상 발생함)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <afxdb.h>
#include <conio.h>
int main()
{
    int nRetCode = 0;
 
    HMODULE hModule = ::GetModuleHandle(nullptr);
 
    if (hModule != nullptr)
    {
        // MFC를 초기화합니다. 초기화하지 못한 경우 오류를 인쇄합니다.
        if (!AfxWinInit(hModule, nullptr, ::GetCommandLine(), 0))
        {
            // TODO: 오류 코드를 필요에 따라 수정합니다.
            wprintf(L"심각한 오류: MFC를 초기화하지 못했습니다.\n");
            nRetCode = 1;
        }
        else
        {
            // TODO: 응용 프로그램의 동작은 여기에서 코딩합니다.
            CDatabase db;
            /******
            BOOL b = db.OpenEx("DSN=student", 0);
            // 원래 ODBC에서 열어야 하나 윈도우10에서 실행하면 OS에서 실행할 수 없다고 에러 창 뜬다.
            *******/
            CString strConnection("DRIVER={Microsoft Access Driver (*.mdb)};DBQ=Student.mdb;UID=;PWD=");
            if (db.OpenEx(strConnection/*, CDatabase::noOdbcDialog*/== FALSE)
            {
                cout << (LPCTSTR)"데이터베이스 접속실패!" << endl;
                _getch();
                return nRetCode;
            }
            CRecordset rs(&db);
            rs.Open(CRecordset::dynaset, "SELECT * FROM Table1");
            
            // 레코드 출력
            CString str;
            while (!rs.IsEOF())
            {
                rs.GetFieldValue(short(0), str);
                cout << (LPCTSTR)str << " ";
                rs.GetFieldValue(short(1), str);
                cout << (LPCTSTR)str << " ";
                rs.GetFieldValue(short(2), str);
                cout << (LPCTSTR)str << " ";
                rs.GetFieldValue(short(3), str);
                cout << (LPCTSTR)str << endl;
                rs.MoveNext();
            }
            rs.Close();
            db.Close();
            _getch(); // 도스창 확인용
        }
    }
    else
    {
        // TODO: 오류 코드를 필요에 따라 수정합니다.
        wprintf(L"심각한 오류: GetModuleHandle 실패\n");
        nRetCode = 1;
    }
 
    return nRetCode;
}
cs

1. DB 객체 생성

BOOL CDatabase::OPenEx(LPCTSTR lpszConnectString, DWORD dwOptions = 0);

lpszConnectString
사용할 데이터 원본 이름과 ID, 암호 등을 문자열로 넘겨준다. ID와 암호가 없는 경우 위 코드 처럼 생략해도 된다. 데이터 원본 이름과 ID, 암호를 모두 사용한다면 아래 같이 한다.
"DSN=Student;UID=SA;PWD=abc123"

dwOptions
비트 매스크로 옵션을 지정한다. 기본값인 0을 사용하면 읽기와 쓰기 모드로 DB룰 접근하며, lpszConnectString 정보가 충분치 않을 경우 자동으로 대화상자가 열리고 이때 DB파일을 지정해주면 된다.

2. 레코드셋 객체 생성

CRecordset::CRecordset(CDatabase* pDatabase = NULL);

pDatabase
DB 객체의 주소를 나타낸다. 클래스 위저드를 이용하여 코드를 생성한 경우에는 pDatabase 에 기본값인 NULL을 사용하는 경우가 많으며, 이 경우 CRecordset 클래스에서 내부적으로 DB 객체를 생성한다.

BOOL CRecordset::OpenEx(UINT nOpenType = AFX_DB_USE_DEFAULT_TYPE,
LPCTSTR lpszSQL = NULL, DWORD dwOptions = none);

nOpenType

nOpenType 종류 

의미 

CRecordset::dynaset

 양방향 스크롤을 지원하며, 다른 사용자가 변경한 대부분의 내용(레코드 삽입은 제외)이 레코드셋에 반영된다.

CRecordset::snapshot 

 양방향 스크롤을 지원하며, 다른 사용자가 변경한 내용이 레코드셋에 반영되지 않는다.

 CRecordset::dynamic

 양방향 스크롤을 지원하며, 다른 사용자가변경한 모든 내용이 레코드셋에 반영된다. 시스템 리소스를 가장 많이 사용하며, ODBC 드라이버에 따라 지원하지 않는 경우도 있으므로 주의해야 한다.

 CRecordset::forwardOnly

 전방향(Forward) 스크롤만 지원하며, 레코드를 읽는 것만 가능하다. 시스템 리소스를 가장 적게 사용한다.

lpszSQL
SQL SELECT 문을 여기에 사용하면 조건에 맞는 레코드셋을 얻을 수 있다.

dwOptions
읽기 전용(CRecordset::readOnly), 추가전용(CRecordset::appendOnly) 등 다양한 옵션이 있으니, MSDN을 참조하기 바란다.

3. 레코드 출력

CRecordset::Open()을 이용하여 레코드셋을 얻으면, 레코드셋 객체는 항상 현재 레코드(Current Record)를 가지고 있게 된다. CRecordset 클래스는 현재 레코드를 다른 위치로 바꿀 수 있는 다양한 멤버함수를 제공하며, 이를 이용하면 코든 레코드에 접근할 수 있다.

현재 레코드 변경 함수명

 기능

 MoveFirst()

 첫 번째 레코드를 현재 레코드로 설정한다. 

 MoveLast()

 마지막 레코드를 현재 레코드로 설정한다.

 MoveNext()

 다음 위치의 레코드를 현재 레코드로 설정한다.

 MovePrev()

 이전 위치의 레코드를 현재 레코드로 설정한다.

 현재 레코드 위치 판단 함수

기능 

 IsBOF()

 현재 레코드가 첫 번째 레코드 바로 전 위치로 설정되었다면 TRUE를 리턴한다. 레코드가 전혀 없는 경우에도 TRUE를 리턴한다.

 IsEOF()

 현재 레코드가 마지막 레코드 바로 다음 위치로 설정되었다면 TRUE를 리턴한다. 레코드가 전혀 없는 경우에도 TRUE를 리턴한다.

현재 레코드의 각 필드(Filed)를 출력하려면 다음과 같은 함수를 사용한다. ,

void CRecordset::GetFieldValue(short nIndex, CString& strValue);

nIndex
필드를 나타내는 인덱스(0 부터 시작) 다. MFC에서는 반드시 short 형변환해야 한다. (40행 참고)

strValue
해당 필드의 데이터가 저장된다.

4. 종료

레코드셋과 DB 객체 사용이 끝나면 각각 Close() 를 호출해야 한다. 두 객체 모두 Close() 를 호출하면 다른 레코드셋 이나 DB를 위해 객체를 재사용할 수 있다. 즉, 레코드셋 객체의 경우 Open()으로 얻은 레코드셋을 모두 사용했다면 Close()를 호출한 후 다시 Open()을 호출해서 새로운 레코드셋을 얻을 수 있다.

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31