SMO中的Transfer类没有兼容的兼容性设置

时间:2016-05-11 12:13:24

标签: c# sql-server smo

我正在编写一个SMO应用程序,它将一个数据库的模式复制到另一个数据库中。

为此,我使用Transfer库中的SmoExtended.dll类。

示例代码为:

Database sourceDatabase = sqlServer.Databases[ASourceName];
Transfer t = new Transfer(sourceDatabase);
t.CopyAllObjects = true;
t.CopyData = false;
t.Options.DriAll = true;
t.Options.Triggers = true;
t.DestinationDatabase = ADestinationName;
t.DestinationServer = sqlServer.Name;
t.DestinationLogin = sqlServer.ConnectionContext.Login;
t.DestinationPassword = sqlServer.ConnectionContext.Password;
Database destinationDatabase = new Database(sqlServer, ADestinationName);
destinationDatabase.CompatibilityLevel = CompatibilityLevel.Version100;
destinationDatabase.Create();
t.TransferData();
destinationDatabase.AutoClose = false;
destinationDatabase.Alter();

我收到错误Version100 database compatibility level is not supported.

我正在使用版本100程序集文件夹中的SMO库。 我正在复制的数据库和目标数据库都在同一服务器实例上。 服务器是SQL Server 2012

我已经尝试了所有可用的兼容级别(80,90,100,110),没有工作。我每次都会收到错误。

但是,如果我使用版本110的SMO库,一切都按预期工作,数据库就会创建并复制模式。

但是,有一个原因我不能使用版本110的库,因为我们的客户端使用的是SQL Server 2008 R2,这是v100,而使用2008R2的机器没有使用的SDK版本110。

PS:源数据库兼容级别设置为100。

我知道如何在2008R2和2012以及2014年使用v100库(这是支持v100的最后一个版本)?

1 个答案:

答案 0 :(得分:0)

解决方案1 ​​ :(简单,非常少的工作)

根据Ben Thul的建议,可以使用单个版本的库(例如110)并将它们与应用程序一起发送,或让客户端安装SQL Server库包。 我已经使用SQL Server 2014库测试了这种方法。为了实现这个目标,我不得不下载:
1. Microsoft SQL Server系统CLR类型(SQLSysClrTypes.msi)
2.共享管理对象(SharedManagementObjects.msi)

我选择使用x86库,总共为9.3MB。这两个库足以获得所需的所有SMO库。

解决方案2 :(更难但仍然很容易,还有更多工作)

我想出了一个比解决方案1更难实现的想法,但它确实有效。

我们的想法是为每个版本的SQL Server创建单独的DLL文件,并动态加载这些DLL。

步骤如下:

  1. 安装或下载Unmanaged exports library
  2. 为单个目标SQL Server版本创建新的DLL项目。 例如2008.dll2012.dll ...
  3. 在每个dll中,我引用相应的SMO库。例如 2008.dll我引用了来自..\100\SDK\Assembly的DLL,用于SQL server 2012我会做2012.dll并参考..\110\SDK\Assemby 等等。
  4. 导出我在主要呼叫时需要的功能 应用。
  5. [DllExport("Copy", System.Runtime.InteropServices.CallingConvention.StdCall)]
    public static void Copy(string AInstance, string AUser, string APass, string ASourceName, string ADestinationName)
    1. 定义加载和卸载DLL的函数
    2. [DllImport("kernel32.dll")]  
      public static extern IntPtr LoadLibrary(string dllToLoad);  
      [DllImport("kernel32.dll")]  
      public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);  
      [DllImport("kernel32.dll")]  
      public static extern bool FreeLibrary(IntPtr hModule);
      1. 定义要使用的函数委托。
      2. [UnmanagedFunctionPointer(CallingConvention.StdCall)]
        private delegate bool CopyDB(string AInstance, string AUser, string APass, string ASourceName, string ADestinationName);
        1. 根据SQL Server版本
        2. 加载,运行和卸载
          if ( Server.Version.Major == 10 ) {
            IntPtr lib8 = LoadLibrary("2008.dll");
            IntPtr workFunc = GetProcAddress(lib8, "Copy");
            CopyDB dbc = ( CopyDB )Marshal.GetDelegateForFunctionPointer(workFunc, typeof(CopyDB));
            dbc(SqlInstance, SqlLogin, SqlPassword, ASourceName, ADestinationName);
            FreeLibrary(lib8);
          } else if ( Server.Version.Major == 11 ) {
            IntPtr lib12 = LoadLibrary("2012.dll");
            IntPtr workFunc = GetProcAddress(lib12, "Copy");
            CopyDB dbc = ( CopyDB )Marshal.GetDelegateForFunctionPointer(workFunc, typeof(CopyDB));
            dbc(SqlInstance, SqlLogin, SqlPassword, ASourceName, ADestinationName);
            FreeLibrary(lib12);
          } else .....

          最后一步可以进一步概括。如果我们要构建名为<version>.dll的dll,我们可以跳过版本检查,例如10.dll11.dll12.dll。这样就不再需要if .. else ..了,正在加载的库的名称将在运行时由Server.Version.Major

          的值生成

          这种方法的积极方面是这些目标DLL文件只需要大约7KB(至少我的场景),这比CLR和SMO.msi库包要少得多。它还保证将使用受支持的SMO库。此外,一旦发布了新版本的SQL Server,就可以将单个dll分发给客户端,并且应用程序将很乐意将其用于新安装的实例。