【问题标题】:How to attach to an MDF database file using OLEDB in C++?如何在 C++ 中使用 OLEDB 附加到 MDF 数据库文件?
【发布时间】:2012-01-21 03:35:44
【问题描述】:

我的 C++ 代码成功地恢复了 SqlServer 数据库备份文件,然后使用 OLEDB API 从生成的数据库中提取了必要的信息。

这是我的 C++ 代码,最后我得到了一个 IDBCreateCommand 实例,可用于对恢复的数据库执行各种查询:

DB::DB(LPCWSTR wszDataSource, LPCWSTR wszBackupFilePath, LPCWSTR wszRestoreFolderPath)
{
  fs::path backupFilePath = fs::canonical(wszBackupFilePath).make_preferred();
  fs::path restoreFolderPath = fs::canonical(wszRestoreFolderPath).make_preferred();
  std::wstring db = backupFilePath.leaf().stem().wstring();
  boost::wformat restoreQueryFmt(L"RESTORE DATABASE [%2%] FROM DISK = N'%1%' WITH REPLACE, STATS = 10, MOVE N'%2%' TO N'%3%\\%2%.mdf', MOVE N'%2%_log' TO N'%3%\\%2%.LDF'");
  std::wstring query = (restoreQueryFmt % backupFilePath.wstring() % db % restoreFolderPath.wstring()).str();

  IDBInitializePtr spDBInitialize;
  HRESULT hr = spDBInitialize.CreateInstance(CLSID_SQLNCLI10, NULL);
  if (REGDB_E_CLASSNOTREG == hr)
  {
    hr = spDBInitialize.CreateInstance(CLSID_SQLNCLI, NULL);
  }
  _HRESULT_CHECK3(spDBInitialize, hr);

  _variant_t vDataSource(wszDataSource);
  _variant_t vAuth(L"SSPI");

  DBPROP dbprop[2];          // property used in property set to initialize provider

  dbprop[0].dwPropertyID = DBPROP_INIT_DATASOURCE;
  dbprop[0].dwOptions  = DBPROPOPTIONS_REQUIRED;
  dbprop[0].vValue = vDataSource;

  dbprop[1].dwPropertyID  = DBPROP_AUTH_INTEGRATED;
  dbprop[1].dwOptions = DBPROPOPTIONS_REQUIRED;
  dbprop[1].vValue = vAuth;

  DBPROPSET dbpropset[1];        // Property Set used to initialize provider
  dbpropset[0].guidPropertySet = DBPROPSET_DBINIT;
  dbpropset[0].rgProperties  = dbprop;
  dbpropset[0].cProperties = sizeof(dbprop)/sizeof(dbprop[0]);

   // Set initialization properties.
  IDBPropertiesPtr spDBProperties = spDBInitialize;

  _HRESULT_CHECK(spDBProperties, SetProperties(1, dbpropset));
  _HRESULT_CHECK(spDBInitialize, Initialize());

  IDBCreateSessionPtr spCreateSession = spDBInitialize;
  _HRESULT_CHECK(spCreateSession, CreateSession(NULL, IID_IDBCreateCommand, reinterpret_cast<IUnknown **>(&m_spDBCreateCommand)));

  ICommandTextPtr spCommandText;
  _HRESULT_CHECK(m_spDBCreateCommand, CreateCommand(NULL, IID_ICommandText, reinterpret_cast<IUnknown **>(&spCommandText)));

  _HRESULT_CHECK(spCommandText, SetCommandText(DBGUID_SQL, query.c_str()));
  _HRESULT_CHECK(spCommandText, Execute(NULL, IID_NULL, NULL, NULL, NULL));
  _HRESULT_CHECK(spCommandText, SetCommandText(DBGUID_SQL, (boost::wformat(L"USE \"%1%\"") % db).str().c_str()));
  _HRESULT_CHECK(spCommandText, Execute(NULL, IID_NULL, NULL, NULL, NULL));
}

它的作用是:

  1. 使用给定数据源(如“.\SQLEXPRESS”)和 SSPI 集成身份验证方案初始化新的数据库连接。
  2. 执行RESTORE DATABASE T-SQL 语句,像这样:RESTORE DATABASE [my_db] FROM DISK = N'c:\temp\my_db.ebf' WITH REPLACE, STATS = 10, MOVE 'my_db' TO N'c:\temp\my_db.mdf', MOVE N'my_db_log' TO N'c:\temp\my_db.LDF'
  3. 通过运行USE "my_db" 将新数据库用于后续查询

所以,我可以毫无问题地恢复数据库备份文件并从那里继续操作。

现在我面临另一个问题。假设没有备份文件,而是一个已经存在的 MDF 文件 - 如何使用 OLEDB C++ API 附加到它?

谢谢。

编辑

假设 .mdf 文件伴随着数据库引擎所需的所有文件 - .ldf 和其他需要的文件。

【问题讨论】:

    标签: c++ sql-server oledb


    【解决方案1】:

    如果你只有一个 MDF 文件,你就不能附加一个数据库,因为那充其量只是数据库的一半。您需要一个 MD 和一个 LDF。以及构成原始数据库的任何其他 NDF 或辅助 LDF 文件。

    假设你的 MDF 和 LDF 分别为 %1% 和 %3%,那么你所要做的就是执行这个语句:

    CREATE DATABASE [%2%] 
      ON (FILENAME=N'%1%')
      , (FILENAME=N'%3')
      FOR ATTACH;
    

    How to: Move a Database Using Detach and Attach (Transact-SQL)

    单独附加和 MDF 的选项确实存在(使用 FOR ATTACH_REBUILD_LOG),但它带有许多警告,因为它仅适用于完全关闭的数据库(否​​则可能导致数据库损坏)。如果您缺少辅助 NDF 文件,则无法附加数据库。

    【讨论】:

    • 顺便说一句,您是否考虑过使用托管 C++ 和 SMO,或者混入一个利用 SMO 并通过 COM 向您的应用程序公开所需功能的托管 DLL?
    • 我的应用程序必须处理三个数据库引擎,其中一个是嵌入式 mysql (libmysqld.dll) 服务器,没有托管包装器。因此我决定一直使用原生 C++。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-14
    相关资源
    最近更新 更多