如何部署 SQL Server Compact Edition 4.0?

Posted

技术标签:

【中文标题】如何部署 SQL Server Compact Edition 4.0?【英文标题】:How to deploy SQL Server Compact Edition 4.0? 【发布时间】:2012-05-31 04:13:37 【问题描述】:

如何部署Microsoft SQL Server Compact 4.0?


SQL Server Compact Edition(目前为 4.0 版)是:

一个免费的嵌入式数据库,软件开发人员可以使用它来构建 Windows 桌面应用程序。它占用空间小,并支持在应用程序文件夹中私有部署其二进制文件。

但是您如何实际部署它?

微软说它可以是deployed within the application folder (good) and supports xcopy deployment。 微软还表示它不能是deployed within the application folder (bad), and does not support xcopy deployment。 有些人有examples of it using simple xcopy deployment,但他们没有详细说明完成部署所需的细节

问题是您不能使用 ADO OLEdb 提供程序,除非它已注册。必须以管理员身份注册 OLEDb 提供程序。这意味着 SQL Server Compact 版本会因非管理员用户而失败。

SQL Server Compact 4.0 附带一个redist_enu.txt 文件:

列出的 .exe 文件每个都将其随附的组件安装到目标计算机上的特定位置。这有助于确保可维护性和技术支持。这些 .exe 文件中包含的 .dll 文件也可在此 redist.txt 中单独获得。但是,这些单独的 .dll 的分发可能会导致可用性问题。更多详情请见http://go.microsoft.com/fwlink/?LinkId=94589

通过 BreadCrumb 进行私有部署检测:仅本机堆栈的私有部署和通过 Assembly.LoadFrom()、.local 文件或使用 DLL/COM 重定向策略显式加载 SQL Server Compact 程序集不受支持,可能会导致在可维护性问题上。有关详细信息,请参阅http://support.microsoft.com/kb/835322 和 http://msdn2.microsoft.com/en-us/library/aa375142.aspx

Microsoft SQL Server Compact 4.0

SSCERuntime_x86-ENU.exe SSCERuntime_x86-DEU.exe SSCERuntime_x86-FRA.exe SSCERuntime_x86-JPN.exe SSCERuntime_x86-RUS.exe SSCERuntime_x86-ESN.exe SSCERuntime_x86-ITA.exe SSCERuntime_x86-KOR.exe SSCERuntime_x86-CHT.exe SSCERuntime_x86-CHS.exe SSCERuntime_x64-ENU.exe SSCERuntime_x64-DEU.exe SSCERuntime_x64-FRA.exe SSCERuntime_x64-JPN.exe SSCERuntime_x64-RUS.exe SSCERuntime_x64-ESN.exe SSCERuntime_x64-ITA.exe SSCERuntime_x64-KOR.exe SSCERuntime_x64-CHT.exe SSCERuntime_x64-CHS.exe sqlcese40.dll sqlceqp40.dll sqlceoledb40.dll sqlceca40.dll sqlceme40.dll sqlcecompact40.dll sqlceer40en.dll sqlceer40cn.dll/sqlceer40zh-CHS.dll sqlceer40de.dll sqlceer40es.dll sqlceer40fr.dll sqlceer40it.dll sqlceer40ja.dll sqlceer40ko.dll sqlceer40tw.dll/sqlceer40zh-CHT.dll sqlceer40ru.dll System.Data.SqlServerCe.dll System.Data.SqlServerCe.Entity.dll

但它没有提供有关如何重新分发 SQL Server Compact 4.0 的任何信息。

在未记录的Program Files 文件夹周围随机拼写我发现了 7 个 dll:

C:\Program Files\Microsoft SQL Server Compact Edition\v4.0\
      sqlceoledb40.dll
      sqlceqp40.dll
      sqlcese40.dll
      sqlceca40.dll
      sqlcecompact40.dll
      sqlceer40EN.dll
      sqlceme40.dll

注意:还有一些子文件夹有更多的dll

我尝试将这 7 个 dll 复制到一个文件夹中,并尝试使用 the connection string 打开一个 ADO Connection:

Provider=Microsoft.SQLSERVER.CE.OLEDB.4.0;Data Source="store.sdf"

但它失败了0x80004005 Unspecified error

i tried frobbing the widget, but it grobbed the frobber.

【问题讨论】:

我自己从来没有这样做过,但是文档不清楚吗? msdn.microsoft.com/en-us/library/aa983326(v=vs.110).aspx 在此处查看我的博文:erikej.blogspot.com/2011/02/… 将 SQL Server Compact 4.0 与桌面专用部署和安装项目 (MSI) 结合使用(第 2 部分) 您引用了app.config,我认为这意味着一个 .NET 应用程序。我碰巧正在使用带有 xcopy 部署的本机应用程序。 @Pondlife 如何:使用应用程序部署 SQL Server Compact 4.0 数据库页面非常清晰。不幸的是,它也不起作用。他们假设一个 .NET 应用程序,并忽略 OLEDB COM dll sqlceoledb40.dll 所需的注册。 在文档为 gone forever 之前,通过支持它来记录此 post! 【参考方案1】:

我已经创建了解决方案。

SQL Server Compact Edition 由 7 个 dll 组成:

sqlceme40.dll 未记录的本机平面 API 库(.net System.Data.SqlServerCe.dll 程序集是此 dll 的包装器) sqlceca40.dll 一个实现 EngineReplicationError 和其他一些 COM 对象的 COM dll sqlceoledb40.dll 为 SSCE 实现 OLEdb 提供程序的 COM dll(允许使用 ADO) sqlcese40.dll 未知 sqlceqp40.dll 未知 sqlcecompact40.dll 未知 sqlceer40en.dll 未知

尝试简单地发送这些 dll 的问题是其中两个是 COM 对象。 COM 对象 dll 需要注册,例如:

>regsvr32 sqlceca40.dll
>regsvr32 sqlceoledb40.dll

问题在于注册 COM 对象需要管理 权限 (using a global solution to solve a local problem)。这意味着您的用户会

必须安装您的应用程序(您不想这样做) 要求您的用户拥有管理权限(您不想这样做)

幸运的是,从 2001 年开始使用 Windows XP,Microsoft 解决了这个常见问题:Registration-Free COM。

首先,您将声明您的应用程序在 SQL Server Compact Edition 4.0 上具有“依赖关系”。您可以通过编写程序集清单来做到这一点:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 
    <assemblyIdentity 
        version="1.0.0.0"
        processorArchitecture="X86"
        name="client"
        type="win32"
    /> 

    <description>Hyperion Pro</description> 

    <!-- We have a dependancy on SQL Server CE 4.0 -->
    <dependency>
        <dependentAssembly>
            <assemblyIdentity
                type="win32"
                name="Microsoft.SQLSERVER.CE.4.0"
                version="4.0.0.0" processorArchitecture="x86"
            />
        </dependentAssembly>
    </dependency>
    <!-- We are high-dpi aware on Windows Vista -->
    <asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
        <asmv3:windowsSettings
            xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
            <dpiAware>true</dpiAware>
        </asmv3:windowsSettings>
    </asmv3:application>

    <!-- We were designed and tested on Windows 7 -->
    <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
        <application>
            <!--The ID below indicates application support for Windows 7 -->
            <supportedOS Id="35138b9a-5d96-4fbd-8e2d-a2440225f93a"/>
            <!--The ID below indicates application support for Windows Vista -->
            <!--supportedOS Id="e2011457-1546-43c5-a5fe-008deee3d3f0"/-->
        </application>
    </compatibility>

    <!-- Disable file and registry virtualization -->
    <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
        <security>
            <requestedPrivileges>
                <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
            </requestedPrivileges>
        </security>
    </trustInfo>
</assembly>

您可以将此文件旁边放在您的可执行文件(如Hyperion.exe.manifest),或者您可以将它作为RT_MANIFEST 资源构建到您的应用程序中。

请注意,我们依赖于名为 Microsoft.SQLSERVER.CE.4.0 的程序集。我们首先通过创建一个名为

目录来创建这个程序集:

Microsoft.SQLSERVER.CE.4.0

当您部署您的应用程序时,您会将构成此“程序集”的所有 7 个 dll 连同一个特殊的 .manifest 文件一起放入此 Microsoft.SQLSERVER.CE.4.0 子文件夹中:

?C:\
╰──?Users
   ╰──?Ian
      ╰──?AppData
         ╰──?Local
            ╰──?Hyperion Pro
               ├──?Hyperion.exe
               ├──?Hyperion.exe.manifest
               ╰──?Microsoft.SQLSERVER.CE.4.0
                  ├──?sqlceme40.dll
                  ├──?sqlceca40.dll
                  ├──?sqlceoledb40.dll
                  ├──?sqlcese40.dll
                  ├──?sqlceqp40.dll
                  ├──?sqlcecompact40.dll
                  ├──?sqlceer40en.dll
                  ╰──?Microsoft.SQLSERVER.CE.4.0.manifest

换句话说,应用程序文件夹包含您的应用程序,以及 Microsoft.SQLSERVER.CE.4.0 文件夹:

 Directory of C:\Users\Ian\AppData\Local\Hyperion Pro

05/29/2012  09:23 AM         1,899,008 Hyperion.exe
05/28/2012  01:46 PM             1,587 Hyperion.exe.manifest
05/29/2012  09:27 AM    <DIR>          Microsoft.SQLSERVER.CE.4.0
           2 File(s)      1,900,675 bytes
           1 Dir(s)  20,851,503,104 bytes free

您任务的下一部分是定义Microsoft.SQLSERVER.CE.4.0.manifest 文件。免注册 COM 允许清单文件声明所有 COM 对象及其 clsid。这需要大量的逆向工程。但是 SQL Server Compact Edition 4.0 的程序集清单是:

Microsoft.SQLSERVER.CE.4.0.manifest

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

<assemblyIdentity 
       type="win32"
       name="Microsoft.SQLSERVER.CE.4.0"
       processorArchitecture="x86"
       version="4.0.0.0" />

<!-- OLEDB Provider -->
<file name = "sqlceoledb40.dll">
    <comClass
            description = "Microsoft SQL Server Compact OLE DB Provider for Windows"
            clsid="2006C53A-C915-41EA-BAA9-9EAB3A1FBF97"
            threadingModel = "Both"
            progid = "Microsoft.SQLSERVER.CE.OLEDB.4.0" />
</file>

<!-- Native flat engine library -->
<file name="sqlceme40.dll" />

<!-- Engine and Replication COM object -->
<file name="sqlceca40.dll">
    <comClass description="Active SSCE Engine Object"
            clsid="68D45319-3702-4837-9F8E-DA6845D82482"
            threadingModel="Both"
            progid="SSCE.Engine.4.0" />
    <comClass description="SSCE Error Object"
            clsid="36228F21-B5C7-4054-8DC2-47D3E236E8B5"
            threadingModel="Both"
            progid="SSCE.Error.4.0" />
    <comClass description="SSCE Param Object"
            clsid="0B3A7B75-A9B0-4580-9AA5-1A7DA47AD1CB"
            threadingModel="Both"
            progid="SSCE.Param.4.0" />
    <comClass description="Active SSCE Replication Object"
            clsid="11D5B2D4-26A4-44F5-A48B-0FAC3A919ED8"
            threadingModel="Both"
            progid="SSCE.Replication.4.0" />
    <comClass description="Active SSCE remote data access Object"
            clsid="58BC9AD6-BF11-40B3-9AB1-E3F2ED784C08"
            threadingModel="Both"
            progid="SSCE.RemoteDataAccess.4.0" />

    <typelib tlbid="CE4AACFA-3CFD-4028-B2D9-F272314F07C8"
            version="4.0" 
            helpdir=""/>
</file>

<comInterfaceExternalProxyStub 
    name="ISSCEEngine"
    iid="10EC3E45-0870-4D7B-9A2D-F4F81B6B7FA2"
    proxyStubClsid32="00020424-0000-0000-C000-000000000046"
    baseInterface="00000000-0000-0000-C000-000000000046"
    tlbid = "CE4AACFA-3CFD-4028-B2D9-F272314F07C8" />

<comInterfaceExternalProxyStub 
    name="ISSCEError"
    iid="31155A3B-871D-407F-9F73-DEBFAC7EFBE3"
    proxyStubClsid32="00020424-0000-0000-C000-000000000046"
    baseInterface="00000000-0000-0000-C000-000000000046"
    tlbid = "CE4AACFA-3CFD-4028-B2D9-F272314F07C8" />

<comInterfaceExternalProxyStub 
    name="ISSCERDA"
    iid="4F04F79D-1FF1-4DCD-802B-3D51B9356C14"
    proxyStubClsid32="00020424-0000-0000-C000-000000000046"
    baseInterface="00000000-0000-0000-C000-000000000046"
    tlbid = "CE4AACFA-3CFD-4028-B2D9-F272314F07C8" />

<comInterfaceExternalProxyStub 
    name="ISSCEParams"
    iid="A78AFF90-049C-41EC-B1D8-665968AAC4A6"
    proxyStubClsid32="00020424-0000-0000-C000-000000000046"
    baseInterface="00000000-0000-0000-C000-000000000046"
    tlbid = "CE4AACFA-3CFD-4028-B2D9-F272314F07C8" />

<comInterfaceExternalProxyStub 
    name="ISSCEParam"
    iid="A9876C60-2667-44E5-89DB-E9A46ED392C0"
    proxyStubClsid32="00020424-0000-0000-C000-000000000046"
    baseInterface="00000000-0000-0000-C000-000000000046"
    tlbid = "CE4AACFA-3CFD-4028-B2D9-F272314F07C8" />

<comInterfaceExternalProxyStub 
    name="ISSCEErrors"
    iid="C40143CA-E9F9-4FF4-B8B4-CC02C064FC1B"
    proxyStubClsid32="00020424-0000-0000-C000-000000000046"
    baseInterface="00000000-0000-0000-C000-000000000046"
    tlbid = "CE4AACFA-3CFD-4028-B2D9-F272314F07C8" />

<comInterfaceExternalProxyStub 
    name="ISSCEMerge"
    iid="C6EB397F-D585-428D-A4F4-454A1842CB47"
    proxyStubClsid32="00020424-0000-0000-C000-000000000046"
    baseInterface="00000000-0000-0000-C000-000000000046"
    tlbid = "CE4AACFA-3CFD-4028-B2D9-F272314F07C8" />

<file name="sqlceqp40.dll" />
<file name="sqlcese40.dll" />
<file name="sqlcecompact40.dll" />
<file name="sqlceer40EN.dll" />

</assembly>

最后一个问题是,就像我们依赖于名为 Microsoft.SQLSERVER.CE.4.0 的程序集一样,SQL Server Compact Edition 4.0 反过来又依赖于名为 Microsoft.VC90.CRT 的程序集。幸运的是,您安装的 SQLCE 附带了此程序集的副本:

?Microsoft.VC90.CRT
├──?Microsoft.VC90.CRT.manifest 
╰──?msvcr90.dll

这意味着最终的目录结构是:

?C:\
╰──?Users
   ╰──?Ian
      ╰──?AppData
         ╰──?Local
            ╰──?Hyperion Pro
               ├──?Hyperion.exe
               ├──?Hyperion.exe.manifest
               ╰──?Microsoft.SQLSERVER.CE.4.0
                  ├──?Microsoft.SQLSERVER.CE.4.0.manifest
                  ├──?sqlceme40.dll
                  ├──?sqlceca40.dll
                  ├──?sqlceoledb40.dll
                  ├──?sqlcese40.dll
                  ├──?sqlceqp40.dll
                  ├──?sqlcecompact40.dll
                  ├──?sqlceer40en.dll
                  ╰──?Microsoft.VC90.CRT
                     ├──?Microsoft.VC90.CRT.manifest
                     ╰──?msvcr90.dll
               

【讨论】:

我的罗宾汉谷仓之旅真是太棒了。有很多更简单的方法:private deployment。您甚至可以更进一步,甚至不将私有程序集和 VC++ 文件复制到您的项目中——只需链接到它们并将 Build Action 设置为 Copy if Newer。 @InteXX 所有这些都需要并假定使用 Visual Studio。还有其他构建本机 Win32/64 可执行文件的 IDE。 是的,你是对的。该特定私有部署过程仅适用于 Visual Studio。其他人将需要另一种方式。这是一篇关于免注册 COM 的精彩文章。当我接下来必须这样做时,我会参考它。干得好。 我不确定您在这里使用“Hyperion”。这是您的应用程序的名称还是必须包含的文字? 它无法在 Windows 10 64 位下运行,除非我将以下文件移动到与可执行文件相同的目录中:sqlcese40.dll、sqlceme40.dll、sqlceqp40.dll。【参考方案2】:

对于 Sql Server Ce 4.0 SP1:

我没有处理所有棘手的部署问题,而是选择将设置文件本身作为 EmbeddedResource 包含到我的 exe 中,并做了这个小帮手:

 public static class RedistHelper
    
        private static readonly ILog Log = LogManager.GetLogger(
                                              MethodBase.GetCurrentMethod().DeclaringType);

        private static readonly string SqlCeRedistName64 = "SSCERuntime_x64-ENU.exe";
        private static readonly string SqlCeRedistName32 = "SSCERuntime_x86-ENU.exe";
        private static readonly Dictionary<string, Assembly> Assemblies = 
                        new Dictionary<string, Assembly>(StringComparer.OrdinalIgnoreCase);

        private static string SqlCeRedistName
        
            get 
            
                return Environment.Is64BitOperatingSystem 
                                       ? SqlCeRedistName64 
                                       : SqlCeRedistName32;
            
        

        public static bool IsSqlCeInstalled()
        
            RegistryKey localKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine,
                                                           RegistryView.Registry64);
            RegistryKey ret = localKey.OpenSubKey(
                    @"SOFTWARE\Microsoft\Microsoft SQL Server Compact Edition\v4.0\ENU");
            return ret != null;
        

        private static byte[] ReadFully(Stream input)
        
            byte[] buffer = new byte[16 * 1024];
            using (MemoryStream ms = new MemoryStream())
            
                int read;
                while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
                    ms.Write(buffer, 0, read);
                return ms.ToArray();
            
        

        public static Assembly OnCurrentDomainOnAssemblyResolve(object sender,
                                                                ResolveEventArgs args)
        
            Assembly dll;
            var name = new AssemblyName(args.Name).Name + ".dll";
            if (!Assemblies.TryGetValue(name, out dll))
            
                Assembly res = typeof(RedistHelper).Assembly;
                using (Stream input =
                           res.GetManifestResourceStream(typeof(RedistHelper), name))
                
                    if (input == null)
                    
                        Log.WarnFormat("Assembly 0 does not contain 1", res, name);
                        return null;
                    
                    dll = Assembly.Load(ReadFully(input));
                    if (dll == null)
                    
                        Log.WarnFormat("Assembly 0 failed to load.", name);
                        return null;
                    
                    Log.InfoFormat("Loaded assembly 0.", name);
                    Assemblies[name] = dll;
                    return dll;
                
            
            return dll;
        

        public static void InstallSqlCe()
        
            using (Stream stream =
                       typeof(RedistHelper).Assembly.GetManifestResourceStream(
                           typeof(RedistHelper), SqlCeRedistName))
            
                Debug.Assert(stream != null);
                byte[] bytes = new byte[(int)stream.Length];
                stream.Read(bytes, 0, bytes.Length);
                string path = Path.Combine(Path.GetTempPath(), SqlCeRedistName);

                if (File.Exists(path))
                    File.Delete(path);

                File.WriteAllBytes(path, bytes);

                Process process = new Process
                                  
                                      StartInfo = new ProcessStartInfo
                                                  
                                                      FileName = path,
                                                      UseShellExecute = true
                                                  
                                  ;
                process.Start();
                process.WaitForExit();
            
        
    

唯一真正让我头疼的是引用 System.Data.SqlServerCe.dll - 它根本不会 IlMerge,所以我在我的 main 中按需加载它:

AppDomain.CurrentDomain.AssemblyResolve += RedistHelper.OnCurrentDomainOnAssemblyResolve;

【讨论】:

【参考方案3】:

不确定是否发生了变化。但是使用最新的 SQL Server CE nuget 包,不再需要应用程序清单。您将获得两组二进制文件:x86 和 amd64。只需将它们复制到 x86 和/或 amd64 子目录下的目标文件夹即可。

|--Your App Dir
   |--x86 (x86 sql ce binaries)
   |--amd64 (amd64 sql ce binaries)

你可以走了。看起来 System.Data.SqlCe.dll 可以自动查找和加载本机二进制文件。如果您的应用仅针对一个平台,您也可以将它们部署在应用目录中。

【讨论】:

以上是关于如何部署 SQL Server Compact Edition 4.0?的主要内容,如果未能解决你的问题,请参考以下文章

使用 C# 应用程序部署 SQL Server Compact

私下部署 sql server compact 3.5 sp2 时出错

SQL Server Express 和 SQL Server Compact Edition

如何使用 SQL Server Management Studio (2008) 在 SQL Server Compact Edition 中创建列

SQL Server Compact 3.5 版数据库访问被拒绝

SQL Server Compact - 计算记录/获取数据库中所有表使用的空间