我正在编写一个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的最后一个版本)?
答案 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。
步骤如下:
2008.dll
,2012.dll
... 2008.dll
我引用了来自..\100\SDK\Assembly
的DLL,用于SQL
server 2012我会做2012.dll
并参考..\110\SDK\Assemby
等等。 [DllExport("Copy", System.Runtime.InteropServices.CallingConvention.StdCall)] public static void Copy(string AInstance, string AUser, string APass, string ASourceName, string ADestinationName)
[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);
[UnmanagedFunctionPointer(CallingConvention.StdCall)] private delegate bool CopyDB(string AInstance, string AUser, string APass, string ASourceName, string ADestinationName);
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.dll
,11.dll
,12.dll
。这样就不再需要if .. else ..
了,正在加载的库的名称将在运行时由Server.Version.Major
这种方法的积极方面是这些目标DLL文件只需要大约7KB(至少我的场景),这比CLR和SMO.msi库包要少得多。它还保证将使用受支持的SMO库。此外,一旦发布了新版本的SQL Server,就可以将单个dll分发给客户端,并且应用程序将很乐意将其用于新安装的实例。