OLEDB 保存 BLOB 到数据库的最简洁代码

/// <summary>通过 OLEDB 模板保存二进制数据到数据库的 BLOB 字段,代码量减少至 MSDN 上推荐代码的几十分之一,SDK、WTL、MFC 通用</summary>
/// <param name="session">传入的 session 应已经正常连接数据库</param>
/// <param name="cmdBlob">外部声明的目的是在出现错误时,外部代码能通过其获取错误,否则也可改为内部声明</param>
/// <param name="sSelectSQL">查询二进制数据的 SQL 语句,需满足:返回一个 BLOB 查询字段且返回唯一记录。例如:SELECT Photo FROM TB_PHOTO WHERE ID=1</param>
/// <param name="pIStream">已写入了二进制(BLOB) 数据的 IStream 接口。</param>
/// <returns>标准 HRESULT</returns>
HRESULT SaveBLOB(CSession& session, CCommand<CManualAccessor>& cmdBlob, LPCTSTR sSelectSQL, IStream* pIStream)
{
	_ASSERT(session.m_spOpenRowset != NULL);	// 传入的 session 应已经正常连接数据库
	_ASSERT(sSelectSQL != NULL);				// 例如:SELECT Photo FROM TB_PHOTO WHERE ID=1
	_ASSERT(pIStream != NULL);					// 已写入了二进制(BLOB) 数据的 IStream 接口。

	HRESULT hResult = 0;

	// 行属性
	CDBPropSet propSet(DBPROPSET_ROWSET);							// 这是行属性
	propSet.AddProperty(DBPROP_IRowsetChange, true);				// 设置支持 IRowsetChange 接口,否则后面 CManualAccessor 的 m_spRowsetChange 接口为空
	propSet.AddProperty(DBPROP_UPDATABILITY, DBPROPVAL_UP_CHANGE);	// 设置结果集允许修改

	// 借用 CManualAccessor 特性简化代码,否则额外需要很长的代码以获取一些接口
	if (FAILED(hResult = cmdBlob.Open(session, sSelectSQL, &propSet)))
		return hResult;

	// 借用 OLEDB 模板函数填充绑定结构 DBBINDING
	DBOBJECT dbObject = { STGM_READ, __uuidof(ISequentialStream) };
	DBBINDING dbBinding = { 0 };
	CAccessorBase::Bind(&dbBinding, 1, DBTYPE_IUNKNOWN, sizeof(IUnknown*), 0, 0, DBPARAMIO_NOTPARAM, 0, 0, 0, &dbObject);

	// 获取 IAccessor 接口并根据 DBBINDING 自行创建 HACCESSOR (CManualAccessor 中未直接提供该 IAccessor 接口)
	CComPtr<IAccessor> pIAccessor = NULL;
	if (FAILED(hResult = cmdBlob.m_spRowsetChange->QueryInterface(IID_IAccessor, (void**)&pIAccessor)))
		return hResult;

	HACCESSOR hAccessor = DB_NULL_HACCESSOR;
	if (FAILED(hResult = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 1, &dbBinding, sizeof(ISequentialStream*), &hAccessor, NULL)))
		return hResult;

	// cmdBlob.CreateAccessor(1, &dbBinding, sizeof(ISequentialStream*));

	// 借用 OLEDB 模板函数,效果与 cmdBlob.GetNextResult() 相同
	if (S_OK != (hResult = cmdBlob.MoveNext()))
		return hResult;

	// 复位 IStream 至开始位置
	if (FAILED(hResult = pIStream->Seek({ 0 }, 0, NULL)))
		return hResult;

	// IStream 继承自 ISequentialStream, 因此可以直接从 IStream 获取 ISequentialStream 接口
	ISequentialStream* pISequentialStream = NULL;//(不能用 CComPtr,这里的 ISequentialStream 接口似乎会自动释放 ...)
	if (FAILED(hResult = pIStream->QueryInterface(IID_ISequentialStream, (void**)&pISequentialStream)))
		return hResult;

	// CManualAccessor 自带的 SetData 不能实现二进制写入,需直接调用 IRowsetChange 的 SetData 方法
	return cmdBlob.m_spRowsetChange->SetData(cmdBlob.m_hRow, hAccessor, &pISequentialStream);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值