用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 的 相 应 文 档