介绍一个增强的数据库类CDataSet
2008-02-26 20:26:33 来源:WEB开发网因为MFC完全支持数据库应用程序的开发,所以大多数数据库应用都使用CDatabase和CRecordset类,并且类向导(Class Wizard)提供了快速简易的方式来使用这两个类。有一点不足的就是当应用程序涉及到多表数据库时,类向导将产生大量的关于记录集的源码文件使得工程给人的感觉很臃肿混乱。
本文介绍如何使用一个模板记录集类来降低类向导所产生的记录集文件的数量,同时增强记录集类(CRecordset)的功能。这个模板记录集类叫做:CDataSet。它的主要目的是降低代码量,为数据对象数组提供一个接口。
CDataSet类定义如下: CDataSet 头文件
这个模板有两个参数:一个是数据对象类,另一个是绑定字段的数量。数据对象类由一组成员变量组成,对应着不同的数据库表的字段,例如:
template class CDataSet : public CRecordset
{
public:
CDataSet(LPCSTR Table, CDatabase* pdb);
T m_Data; // Attached object
CString m_DefaultSQL; // Default SQL SELECT statement
CString m_DefaultSort; // Default SQL ORDER BY clause
CString m_DefaultFilter; // Default SQL WHERE clause
// Operations
public:
virtual BOOL Search(LPCSTR Filter, LPCSTR Sort = NULL, BOOL bFail = FALSE);
virtual BOOL DirectSearch(LPCSTR Filter, LPCSTR Sort = NULL, BOOL bFail = FALSE);
virtual void LoadAll(CArray& A, int N = 0);
virtual void SaveAll(CArray& A);
virtual void Load(T& Data) { Data = m_Data; }
virtual void Store(T& Data);
// Implementation
protected:
virtual CString GetDefaultSQL() { return m_DefaultSQL; }
virtual void DoFieldExchange(CFieldExchange* pFX);
};struct DataObj {
CString Var1;
CString Var2;
int Var3;
float Var4;
// ......
// 成员函数
};
如果将数据对象定义成一个类,而不是一个结构,就必须定义缺省的供类模板使用的构造函数并重载 “=” 操作符(operator=),要不然的话编译会出错。CDataSet的成员变量m_DefaultSQL用来灵活方便地控制SQL数据源,m_DefaultSQL可以是一个表名、表名的列表、或者是任何复杂的SQL语句,还有就是因为m_DefaultSQL可以在运行时被改变,使得相同的类访问不同的表(如果这些表有相同的结构)成为可能。如果默认的SQL发生变化,相应的记录集必须被重新打开。 Load(), Store(), LoadAll() 和 StoreAll() 方法完成单个或多个数据对象的加载和存储操作。LoadAll()的最后一个参数,N,指定要加载记录数的最大值。Search()和 DirectSearch()方法实现改进的搜索能力。Search()使用m_DefaultSort 和 m_DefaultFilter成员变量并且当希望的记录未找到和 bFail为TRUE时丢出异常。DirectSearch()接受一个外部指定的SQL WHERE 从句。以下是这个模板类的实现,它不是很复杂: CDataSet实现
template<class T, int M> CDataSet<T, M>::CDataSet(LPCSTR Table, CDatabase* pdb) :
CRecordset(pdb)
{
m_nFields = M;
m_DefaultSQL = Table;
m_DefaultFilter = "%s";
}
template<class T, int M> BOOL CDataSet<T, M>::Search(LPCSTR Filter,LPCSTR Sort, BOOL bFail)
{
if ( IsOpen() )
Close();
SetStatus("Opening " + m_DefaultSQL + " ...");
if ( Filter )
m_strFilter.Format(m_DefaultFilter, Filter);
else
m_strFilter = "";
m_strSort = Sort;
Open();
// Throw exception if record not found
if ( bFail && IsEOF() )
THROW(new CMyException(m_DefaultSQL + " record not found!"));
return !IsEOF();
}
template<class T, int M> BOOL CDataSet<T, M>::DirectSearch(LPCSTR Filter, LPCSTR Sort, BOOL bFail)
{
if ( IsOpen() )
Close();
SetStatus("Opening " + m_DefaultSQL + " ...");
m_strFilter = Filter;
m_strSort = Sort;
Open();
// Throw exception if record not found
if ( bFail && IsEOF() )
THROW(new CMyException(m_DefaultSQL + " record not found!"));
return !IsEOF();
}
template<class T, int M> void CDataSet<T, M>::LoadAll(CArray<T, T>& A, int N)
{
SetStatus("Loading " + m_DefaultSQL + " ...");
A.RemoveAll();
while ( !IsEOF() && (N == 0 || A.GetSize() < N) )
{
A.Add(m_Data);
MoveNext();
}
}
template<class T, int M> void CDataSet<T, M>::SaveAll(CArray<T, T>& A)
{
SetStatus("Writing " + m_DefaultSQL + " ...");
for ( int i = 0;i < A.GetSize(); i++ )
{
AddNew();
Store(A[i]);
}
}
template<class T, int M> void CDataSet<T, M>::Store(T& Data)
{
SetStatus("Updating " + m_DefaultSQL + " ...");
Edit();
m_Data = Data;
Update();
}
template<class T, int M> void CDataSet<T, M>::Close()
{
CRecordset::Close();
SetStatus("Ready");
}
CDataSet类中许多方法都使用SetStatus()函数,它的作用是显示一个沙漏以及在应用程序状 态条显示当前的操作状态。 void SetStatus(const CString Msg)
{
CFrameWnd* pMainFrame = (CFrameWnd*)AfxGetMainWnd();
if ( pMainFrame )
{
pMainFrame->SetMessageText(Msg);
pMainFrame->UpdateWindow();
if ( strcmp(Msg, "Ready") == 0 )
pMainFrame->EndWaitCursor();
else
pMainFrame->BeginWaitCursor();
}
}
当处理大量数据和执行复杂的查询时,这个函数特别有用。它告诉用户应用程序正在处理数据。
更多精彩
赞助商链接