이번 시간에는 이전에 만들었던 FTP 프로그램과 MSSQL을 연동하는 작업을 해볼까 합니다.
참고로 FTP 프로그램은 MFC로 만들었습니다.
그전에 미리 MSSQL를 설치 해야겠죠?
https://www.microsoft.com/ko-kr/sql-server/sql-server-downloads
공식 홈페이지에 가셔서 설치를 하시면 됩니다!! 저는 express 버전을 설치 했습니다.
이것뿐 아니라 SSMS도 설치를 해야 통합적으로 DB를 보실 수 있습니다.
SSMS(SQL Server Management Studio) 다운로드 - SQL Server Management Studio (SSMS)
SQL_A 및 Azure SQL 인스턴스를 관리하고 구성하려면 최신 버전의 SSMS(SQL Server Management Studio)를 다운로드하세요.
learn.microsoft.com
저는 20.2 버전을 설치했습니다.😊
참고로 설치 하실 때 인스턴스 이름을 묻는 설정이 나옵니다. 이 때 기본 인스턴스로 설치를 하시는게 좋습니다.
기본 인스턴스는 MSSQLSERVER 인데 Express 버전으로 설치를 하시면 SQLEXPRESS로 설치되는 경우가 있습니다. 저는 MSSQLSERVER를 기준으로 잡고 설명을 하겠습니다.
🟧 MSSQL 연동
// pch.h
#import "C:\\Program Files\\Common Files\\System\\ado\\msado15.dll" \
no_namespace \
rename("EOF", "EndOfFile")
데이터 베이스와 연동하기 위해 저는 ADO를 사용했습니다. MFC/C++를 사용해 DB에 접근할 때 가장 많이 사용되는 프레임워크라고 해서 사용했습니다.
ADO에 대해 간단하게 얘기하면 마이크로소프트에서 제공하는 컴포넌트 기반의 데이터 액세스 프레임워크로, 데이터 소스와 상호 작용하기 위한 기능을 제공합니다. ADO는 COM(컴포넌트 객체 모델) 기반으로 개발되어 있으며, 다양한 프로그래밍 언어 (예: Visual Basic, C++, C# 등) 와 환경에서 사용할 수 있습니다.
ADO를 사용하기 위해서는 pch.h 파일에 dll문을 추가해주는 코드를 써줘야 합니다.
BOOL CMFCApplication1Dlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// ADO 초기화
CoInitialize(NULL);
// 데이터 베이스 연결 객체
_ConnectionPtr pConn;
// DB 연결
HRESULT hr = pConn.CreateInstance(__uuidof(Connection));
if (SUCCEEDED(hr)) {
try {
pConn->Open("Provider=SQLOLEDB;Data Source=YOUR IP ADDRESS;Initial Catalog=YOUR DB NAME;User Id=YOUR DB ID;Password=YOUR DB PASSWORD;", "", "", adConnectUnspecified);
}
catch (_com_error& e) {
AfxMessageBox(e.Description());
}
}
else {
AfxMessageBox(_T("Filed to create connection instance."));
}
return TRUE;
}
먼저 ADO를 초기화 시켜준 후 DB 연동을 해야 한다.
_ConnectionPtr 객체를 만들고 DB 연동시킬 DB 이름, IP 주소, ID, PW등을 입력한다.
_ConncetionPtr 객체는 데이터 소스와의 연결을 설정하고 관리하는 객체입니다. 데이터베이스에 대한 연결을 열고 닫거나, 연결된 데이터 소스에 대한 트랜잭션을 관리합니다.
🟥 Select 문
BOOL CDBList::OnInitDialog()
{
CDialogEx::OnInitDialog();
SetWindowText(_T("Log History"));
// Recordset 객체 생성
_RecordsetPtr pRecordset;
CRect rt;
m_DBList.GetWindowRect(&rt);
m_DBList.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
m_DBList.InsertColumn(0, _T("Date"), LVCFMT_LEFT, rt.Width() * 0.3);
m_DBList.InsertColumn(1, _T("Log"), LVCFMT_LEFT, rt.Width() * 0.7);
CString query;
query.Format(_T("Select * From dbo.LogHistory"));
pConn->Execute((LPCTSTR)query, NULL, adCmdText);
pRecordset.CreateInstance(__uuidof(Recordset));
try {
pRecordset->Open((_bstr_t)query, pConn.GetInterfacePtr(), adOpenStatic, adLockReadOnly, adCmdText);
// 데이터가 존재하는 동안 반복
while (!pRecordset->EndOfFile) {
// 각 필드를 변수에 담기
CString Date = (LPCTSTR)(_bstr_t)pRecordset->Fields->GetItem("EventDateTime")->GetValue();
CString Log = (LPCTSTR)(_bstr_t)pRecordset->Fields->GetItem("LogText")->GetValue();
// List Control에 아이템 추가
int nIndex = m_DBList.InsertItem(0, Date); // 첫 번째 열에 ID 추가
m_DBList.SetItemText(nIndex, 1, Log); // 두 번째 열에 Description 추가
// 다음 레코드로 이동
pRecordset->MoveNext();
}
pRecordset->Close();
}
catch (_com_error& e) {
AfxMessageBox(e.ErrorMessage());
}
return TRUE;
}
저는 로그 기록을 보여주는 다이얼로그를 만들었습니다. ListControl를 통해 DB에 저장된 로기 기록을 보여주는 로직입니다.
여기서 Select 문을 통해 쿼리를 적용시키는 코드는 아래와 같습니다.
CString query;
query.Format(_T("Select * From dbo.LogHistory"));
pConn->Execute((LPCTSTR)query, NULL, adCmdText);
pRecordset.CreateInstance(__uuidof(Recordset));
쿼리를 사용해 데이터베이스의 자료를 조회하거나 삽입, 삭제를 하기 위해서는 Recordset 객체가 필요합니다.
Recordset 데이터 소스에서 반환되는 결과 집합을 관리하는 객체입니다. Recordset 객체는 커서를 사용하여 데이터를 순회하고, 필요에 따라 데이터를 추가, 수정, 삭제할 수 있습니다.
또한 저는 추출된 데이터를 Listcontrol에 차례대로 넣어줘야 해서 while 문을 사용해 데이터가 존재안할 때 까지 조회하도록 했습니다.
🟩 Insert 문
try {
CString query;
query.Format(_T("INSERT INTO dbo.LogHistory (EventDateTime,LogText) VALUES ('%s','%s')"), date, newText);
pConn->Execute((LPCTSTR)query, NULL, adCmdText);
}
catch (_com_error& e) {
AfxMessageBox(e.Description());
}
Select 문과 비슷하게 생겼습니다.
변수값을 집에 넣고 싶으시면 데이터 형식을 대입하고 차례대로 변수를 추가하시면 됩니다.
저는 날짜랑 텍스트 값을 넣고 싶어서 위와 같이 썼습니다.
🟫 Delete 문
void CDBList::OnBnClickedButtonDeleteAll()
{
try {
CString query = _T("DELETE FROM dbo.LogHistory");
pConn->Execute((LPCTSTR)query, NULL, adCmdText);
m_DBList.DeleteAllItems();
AfxMessageBox(_T("모든 데이터가 삭제되었습니다."));
}
catch (_com_error& e) {
CString strError;
strError.Format(_T("Error: %s"), (LPCTSTR)e.Description());
AfxMessageBox(strError);
}
}
버튼을 클릭하면 Delete 문이 실행되도록 만들었습니다. 또한 기존의 ListControl의 값들도 모두 삭제시켜줬습니다.😊