用MFC实现在字段中存储变长数组

---- 在 数 据 库 应 用 时, 有 时 会 遇 到 这 样 的 情 况: 记 录 的 某 项 信 息 由 变 长 数 组 构 成。 这 时 传 统 方 法 是 建 立 一 个 新 表, 并 通 过 表 间 的 关 系 来 记 录 将 相 应 数 据 关 联 起 来; 但 是 这 样 实 现 相 对 比 较 复 杂, 而 且 也 不 符 合 思 维 逻 辑。 由 于 该 数 组 整 个 构 成 记 录 的 一 个 具 体 项, 因 此 如 果 能 够 将 它 作 为 一 个 字 段 则 更 加 直 观 些, 同 时 在 一 些 情 况 下 也 比 较 容 易 处 理。 那 么, 下 面 将 向 您 提 供 一 种 这 样 的 方 法。 为 了 说 明 上 的 方 便, 我 首 先 假 定 了 下 面 的 需 求:

---- 在 个 人 简 历 数 据 表 中, 需 要 将 工 作 经 历 分 为 起、 止 时 间、 单 位、 职 位 等 信 息。

---- 在 这 种 情 况, 可 以 分 别 建 立 个 人 简 历 和 工 作 经 历 两 个 表 并 将 之 通 过 关 键 字 进 行 关 联, 从 而 达 到 要 求。 但 也 可 以 采 用 只 建 立 一 个 表 的 方 式 来 完 成 数 据 的 管 理

---- 那 么 如 何 完 成 呢 ? 下 面 将 给 出 具 体 的 实 现。

---- 首 先 建 立 一 个 表Person, 记 录 包 含 个 人 简 历 需 要 的 各 个 字 段, 将 工 作 经 历 作 为 一 个 字 段, 其 类 型 为Image( 在Access 数 据 库 中 为"OLE 对 象")。 下 面 新 建 类CPersonRs。 将 它 与 表Person 对 应 起 来, 并 将 m_dResume 对 应 到 字 段 工 作 经 历 中,m_dResume 的 类 型 为CByteArray 。 下 面 我 们 来 定 义 工 作 定 义 的 基 本 结 构:

class CResumeItem
{
public:
COleDateTime m_timeBegin;
COleDateTime m_timeEnd;
COleDateTime m_strCompany;
COleDateTime m_strTitle;

Void Serialize( CArchive& ar )
};
typedef CArray< CResumeItem, CResumeItem& > CResume;

---- 在CPersonRs 中 定 义 下 面 的 函 数

CPersonRs
{
……
CByteArray m_dResume;
……
void SetResume( CString strName, CResume& resume );
void GetResume( CString strName, CResume& resume );
};

并在相应的文件给出相应的函数的实现;
void CResumeItem::Serialize( CArchive& ar )
{
if ( ar.IsLoading() )
{
ar > > m_timeBegin
> > m_timeEnd
> > m_strCompany
> > m_strTitle;
}
else
{
ar < < m_timeBegin
< < m_timeEnd
< < m_strCompany
< < m_strTitle;
}
}

函数SetResume和GetResume实现如下:
void CPersonRs::SetResume
( CString strName, CResume& resume )
{
…………//根据strName定位到相应的记录
Edit();
CMemFile memFile;
CArchive ar( &memFile, CArchive::store );
Resume.Serialize( ar );
ar.Close();
DWORD dwSize = memFile.GetLength();
LPBYTE lpInfo = memFile.Detach( );
m_dResume.SetSize( dwSize );
memcpy( m_dResume.GetData(),lpInfo,dwSize);
SetFieldNull( &m_dResume, FALSE );
SetFieldDirty( &m_dResume );
ASSERT( CanUpdate() );
Update( );
free( lpInfo );
}

void CPersonRs::GetResume
( CString strName, CResume& resume )
{
…………//根据strName定位到相应的记录
LPBYTE lpInfo;
DWORD dwSize;
dwSize = m_dResume.GetSize();
lpInfo = m_dResume.GetData();
memFile.Attach( lpInfo, dwSize );
CArchive ar( &memFile,CArchive::load );
resume.Serialize( ar );
ar.Close();
memFile.Detach( );
}

---- 通 过SetResume 和GetResume 可 以 方 便 地 将Resume 的 内 容 读 出 或 写 入 到 记 录 的 工 作 经 历 字 段 中, 而 且 更 新 也 相 当 方 便。 这 样 是 就 可 以 在 工 作 经 历 字 段 任 意 个 工 作 经 历 项, 而 且 由 于 是 在 一 个 表, 也 省 去 了 多 表 造 成 的 麻 烦。

---- 不 过, 最 后 需 要 声 明 的 是, 上 述 例 子 的 情 况 根 据 实 际 需 要 可 能 用 多 表, 但 这 里 只 是 借 它 说 明 这 样 一 种 实 现 方 法, 也 许 你 会 在 某 些情 况 下 这 些 会 相 当 简 单 些。 本 文 也 只 给 出 实 现 的 关 键 代 码, 对 于 如 何 使 用MFC 访 问 数 据 库、 序 列 化 机 制 可 以 参 见VC 的 相 应 文 档。