我应该将啥传递给 SQLitePCL.raw.SetProvider() 以避免“'Microsoft.Data.Sqlite.SqliteConnection' 的类型初始化程序引发异常”

Posted

技术标签:

【中文标题】我应该将啥传递给 SQLitePCL.raw.SetProvider() 以避免“\'Microsoft.Data.Sqlite.SqliteConnection\' 的类型初始化程序引发异常”【英文标题】:What should I pass to SQLitePCL.raw.SetProvider() to avoid "The type initializer for 'Microsoft.Data.Sqlite.SqliteConnection' threw an exception"我应该将什么传递给 SQLitePCL.raw.SetProvider() 以避免“'Microsoft.Data.Sqlite.SqliteConnection' 的类型初始化程序引发异常” 【发布时间】:2021-03-27 05:19:22 【问题描述】:

我收到此错误消息:

“Microsoft.Data.Sqlite.SqliteConnection”的类型初始化器 抛出异常。

更明确地说,我得到:

Message = 的类型初始化器 'Microsoft.Data.Sqlite.SqliteConnection' 抛出异常。

Inner Exception = System.Exception: 你需要调用 SQLitePCL.raw.SetProvider()。如果您使用的是捆绑包,这 通过调用 SQLitePCL.Batteries.Init() 来完成。在 SQLitePCL.raw.get_Provider() 在 SQLitePCL.raw.sqlite3_win32_set_directory(Int32 typ,字符串路径)在 Microsoft.Data.Sqlite.Utilities.BundleInitializer.Initialize() 在 Microsoft.Data.Sqlite.SqliteConnection..cctor()

堆栈跟踪 = 在 Microsoft.Data.Sqlite.SqliteConnection..ctor(String 连接字符串)在 CartographerYou.MainPage.InsertMapRecord(字符串 mapName, String mapNotes, Int32 preferredZoomLevel) at CartographerYou.MainPage.btnCre8NewMap_Click(对象发送者, RoutedEventArgs e)

这是 StackTrace 中提到的两种方法(事件处理程序和自定义方法):

private async void btnCre8NewMap_Click(object sender, RoutedEventArgs e)

    try
    
        string mapName = string.Empty;
        string mapNotes = string.Empty;
        int defaultZoomLevel = 1;
        ClearLocations();
        // Popul8 the cmbx
        for (int i = 1; i < 20; i++)
        
            cmbxCre8MapZoomLevels.Items.Add(i.ToString());
        
        ContentDialogResult result = await cntDlgCre8Map.ShowAsync();

        if (result == ContentDialogResult.Primary)
        
            mapName = txtbxMapName.Text;
            mapNotes = txtbxMapNotes.Text;
            defaultZoomLevel = cmbxCre8MapZoomLevels.SelectedIndex + 1;
            // select "Step Into Specific" from context menu
            await InsertMapRecord(mapName, mapNotes, defaultZoomLevel); 
        
        // else do nothing (don't save)                                
    
    catch (Exception ex)
    
        string excMsg = string.Format("0 Inner Exception: 1 Stack Trace: 2", ex.Message, ex.InnerException, ex.StackTrace);
        MessageDialog exceptionMsgDlg = new MessageDialog(excMsg, "btnCre8NewMap_Click");
        await exceptionMsgDlg.ShowAsync();
    


private async Task InsertMapRecord(string mapName, string mapNotes, int preferredZoomLevel)

    path = folder.Path;
    connStr = string.Format(connStrBase, path);
    try
    
        using (SqliteConnection conn = new SqliteConnection(connStr))
        
            String query = "INSERT INTO dbo.CartographerMain " +
                           "(MapName, MapNotes, PreferredZoomLevel) " +
                           "VALUES (@MapName, @MapNotes, @PreferredZoomLevel)";

            using (SqliteCommand cmd = new SqliteCommand(query, conn))
            
                cmd.Parameters.AddWithValue("@MapName", mapName);
                cmd.Parameters.AddWithValue("@MapNotes", mapNotes);
                cmd.Parameters.AddWithValue("@PreferredZoomLevel", preferredZoomLevel);
                await conn.OpenAsync();
                int result = await cmd.ExecuteNonQueryAsync();

                if (result < 0)
                
                    MessageDialog dialog = new MessageDialog("Error inserting data into CartographerMain");
                    await dialog.ShowAsync();
                
            
        
    
    catch (SqliteException sqlex)
    
        string sqlExcMsg = string.Format("0 Inner Exception: 1 Stack Trace: 2", sqlex.Message, sqlex.InnerException, sqlex.StackTrace);
        MessageDialog dialog = new MessageDialog(sqlExcMsg, "InsertMapRecord");
        await dialog.ShowAsync();
    

基于需要调用 SQLitePCL.raw.SetProvider() 的内部异常,我从这里更改了代码:

using (SqliteConnection conn = new SqliteConnection(connStr))

    . . .

...到这个:

SqliteConnection conn = new SqliteConnection(connStr);
SQLitePCL.raw.SetProvider();
. . .

...但我不知道我需要将什么传递给 SetProvider() - 如果这真的是问题的真正解决方案。

这就是我使用该代码得到的结果:

什么需要传递给SetProvider()?

【问题讨论】:

*** 上有一个类似的thread。看来问题是由于缺少必需的参考资料引起的。它错过了 SQLitePCL.raw* 引用。您可以尝试重新安装 NuGet 包或尝试那里发布的其他解决方案。 使用 SQLitePCL 给了我一开始的***。我用谷歌搜索“什么是 SQLitePCL”并得到了这个:SQLitePCL.raw 是一个可移植类库 (PCL),用于对 SQLite 进行低级(原始)访问。此包不提供对应用程序开发人员友好的 API。相反,它提供了一个处理平台和配置问题的 API,可以在此基础上构建更友好的 API。 嗯,该线程上的解决方案是重新安装Microsoft.Data.SQLite NuGet 包,以确保正确安装所有必需的引用。请检查@Tristan Trainer 发布的解决方案。或者你可以试试@René Schindhelm 的解决方案 很好,重新安装(或实际上)安装让我解决了这个问题。事实证明,我安装了 Microsoft.Data.SQLite.Core,但没有安装 Microsoft.Data.SQLite;现在我也有后者(版本 5.0.1)。我收到了不同的错误消息,但这是向前迈出的一步。 另外:你必须在打开连接之前调用SQLitePCL.raw.SetProvider() 【参考方案1】:

我不认为直接使用SQLitePCL.raw 是encouraged:

...这不是你想做的。这不是您用来编写应用程序的那种 SQLite 库。它是 SQLite 的 C API 的一个非常薄的 C# 包装器。它是“原始的”。

假设您对此没问题,您可以考虑使用包装器,例如 sqlite-net(作者在 their page 中提到的选项之一):

    class CartographerMain // the library provides ORM functionality, so i created a simple object based on your example
    
        [PrimaryKey, AutoIncrement]
        public int Id  get; set; 
        public string MapName  get; set; 
        public string MapNotes  get; set; 
        public int PreferredZoomLevel  get; set; 
    

    private async Task InsertMapRecord(string mapName, string mapNotes, int preferredZoomLevel)
    
        var path = "a.db";
        var connStr = string.Format(connStrBase, path);
        SQLiteAsyncConnection db = null;
        try
        
            db = new SQLiteAsyncConnection(connStr);
            await db.CreateTableAsync<CartographerMain>();
            var result = await db.InsertAsync(new CartographerMain  MapName = mapName, MapNotes = mapNotes, PreferredZoomLevel = preferredZoomLevel );

            if (result < 0)
            
                MessageDialog dialog = new MessageDialog("Error inserting data into CartographerMain");
                await dialog.ShowAsync();
            
        
        catch (SQLiteException sqlex)
        
            string sqlExcMsg = string.Format("0 Inner Exception: 1 Stack Trace: 2", sqlex.Message, sqlex.InnerException, sqlex.StackTrace);
            MessageDialog dialog = new MessageDialog(sqlExcMsg, "InsertMapRecord");
            await dialog.ShowAsync();
        
        finally
        
            await db.CloseAsync();
        
    

为了使上面的代码正常工作,我只引用了一个 nuget package - 它取决于 SQLitePCLRaw.bundle_green,我认为它是您无论如何都会安装的包

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="sqlite-net-pcl" Version="1.7.335" />
  </ItemGroup>

</Project>

UPD

假设您在使用 Microsoft.Data.Sqlite 时遇到此异常,我怀疑该问题可能源于 SQLitePCLRaw.bundle_e_sqlite3(底层依赖项)没有为您运行它的环境捆绑本机二进制文件。

如果您安装了Microsoft.Data.Sqlite,您应该将e_sqlite3 捆绑包作为依赖项提供,并且可以尝试使用dynamic 提供程序

SQLitePCL.raw.SetProvider(new SQLitePCL.SQLite3Provider_dynamic_cdecl())

如果这不起作用,您可以搜索 SQLitePCLRaw.provider.e_sqlite3.* 来查找您的特定目标,然后尝试以下操作:

SQLitePCL.raw.SetProvider(new SQLitePCL.SQLite3Provider_e_sqlite3());

【讨论】:

我不怀疑你在这里所说的是真的(“我认为不鼓励直接使用 SQLitePCL.raw”),但这正是 InnerExceptions 所说的。 @B.ClayShannon 澄清一下:您已经在使用Microsoft.Data.Sqlite 了吗?你的目标是什么平台?我还想知道你的项目中是否已经引用了SQLitePCLRaw.bundle_green 使用 Microsoft.Data.Sqlite;这是一个 UWP 应用。 那么您可能需要安装SQLitePCLRaw.provider.e_sqlite3.uwp10 并尝试SQLite3Provider_dynamic_cdecl(我在答案中添加了几个选项) 单独使用 nuget 导入 Microsoft.Data.Sqlite,对我有用。它将正确初始化,无需调用SetProviderBatteries.Init()。如果你有一个多项目的dotnet框架解决方案只需要注意,例如不仅原始项目而且测试项目或启动项目都需要设置相同的nuget。

以上是关于我应该将啥传递给 SQLitePCL.raw.SetProvider() 以避免“'Microsoft.Data.Sqlite.SqliteConnection' 的类型初始化程序引发异常”的主要内容,如果未能解决你的问题,请参考以下文章

我应该将啥传递给 SQLitePCL.raw.SetProvider() 以避免“'Microsoft.Data.Sqlite.SqliteConnection' 的类型初始化程序引发异常”

将啥传递给 clf.predict()?

将啥传递给 Android 的 NDK 以便可以使用 OpenCV 加载图像?

Equatable 的子类将啥传递给超级(Equatable 类)?

将啥传递给 sqlite create_function 任意指针

我应该将啥 DbContext 与 EntityFrameworkCore 一起使用?