c# - 在 C# 中使用带有异步的 SQLite

标签 c# sqlite async-await

我正在努力了解 async/await 关键字和用法,我想我已经掌握了基础知识。但是在我的 SQLite 代码中有些东西不能正常工作。

我正在使用 SQLite.core NuGet package在我一直在做的一个简单项目中。我注意到我编写的异步代码并不异步(如我预期的那样),因此我创建了一个更简单的测试项目来测试我的理解。

在我的测试代码中,我打开了一个到内存数据库的连接(我对基于文件的数据库有同样的问题。在测试代码中,内存更容易),并发出一个“创建表” "命令,使用 ExecuteNonQueryAsync。我不会立即 await 获取结果,而是在最终使用 await 关键字之前向控制台写入一些内容。

我希望在 ExecuteNonQueryAsync 完成之前执行控制台命令,因此在我的测试中我应该看到“1 2 3 4”。但是我得到的是“1 3 2 4”

我使用 SQL Server LocalDB 连接运行相同的测试(运行相同的代码,只有 DbConnection 不同),并得到预期的“1 2 3 4”。所以我想我对 async 的基本理解并没有偏离目标那么远。

我错过了什么?我是否需要对 SQLite 使用特殊的连接字符串以支持 async 方法?它甚至支持它吗?

可以找到我的完整测试项目here .

这是主程序本身:

 namespace DatabaseTest
   {
    using System;
    using System.Data.Common;
    using System.Data.SqlClient;
    using System.Data.SQLite;
    using System.Threading.Tasks;
class Program
{
    static void Main(string[] args)
    {
        Task.WaitAll(TestDatabase(true), TestDatabase(false));
    }

    private static async Task TestDatabase(bool sqLite)
    {
        Console.WriteLine("Testing database, sqLite: {0}", sqLite);
        using (var connection = CreateConnection(sqLite))
        {
            connection.Open();
            var task = ExecuteNonQueryAsync(connection);
            Console.WriteLine("2");
            await task;
            Console.WriteLine("4");
        }
    }

    private static DbConnection CreateConnection(bool sqLite)
    {
        return sqLite ?
            (DbConnection)new SQLiteConnection(string.Format("Data Source=:memory:;")) :
            new SqlConnection(@"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\DatabaseTest.mdf;Integrated Security=True;Connect Timeout=30");
    }

    private static async Task ExecuteNonQueryAsync(DbConnection connection)
    {
        var command = connection.CreateCommand();
        command.CommandText = "CREATE TABLE test (col1 integer);";
        Console.WriteLine("1");
        await command.ExecuteNonQueryAsync();
        Console.WriteLine("3");
    }
}

输出:

Testing database, sqLite: True
1
3
2
4
Testing database, sqLite: False
1
2
3
4

最佳答案

System.Data.SQLite 实现是 100% 同步的。它们没有任何异步重载,微软应该为这种误解负责,因为 SQLiteCommand 使用 *Async 方法的默认实现扩展了 System.Data.Common.DbCommand只调用同步版本:

/// <summary>This is the asynchronous version of <see cref="M:System.Data.Common.DbCommand.ExecuteNonQuery" />. Providers should override with an appropriate implementation. The cancellation token may optionally be ignored.The default implementation invokes the synchronous <see cref="M:System.Data.Common.DbCommand.ExecuteNonQuery" /> method and returns a completed task, blocking the calling thread. The default implementation will return a cancelled task if passed an already cancelled cancellation token.  Exceptions thrown by <see cref="M:System.Data.Common.DbCommand.ExecuteNonQuery" /> will be communicated via the returned Task Exception property.Do not invoke other methods and properties of the <see langword="DbCommand" /> object until the returned Task is complete.</summary>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <exception cref="T:System.Data.Common.DbException">An error occurred while executing the command text.</exception>
public virtual Task<int> ExecuteNonQueryAsync(CancellationToken cancellationToken)
{
  ...
  return Task.FromResult<int>(this.ExecuteNonQuery());
  ...
}

我只是想出了同样困难的方法,我对他们采取的方法不满意,但这就是我们得到的。仅作记录,我认为应该有 NotSupportedException

关于c# - 在 C# 中使用带有异步的 SQLite,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34478104/

相关文章:

swift - 离开函数前执行代码

c# - 创建模型时无法使用上下文异常

c# - JsonConvert 序列化/反序列化锯齿状数组并启用 TypeNameHandling

c# - 使用 MSTSCLib 进行远程桌面连接

python - ImproperlyConfigured : SQLite 3. 需要 8.3 或更高版本(发现 3.7.17)

javascript - 如果花费的时间太长,NodeJS 函数会超时吗?

c# - 如何使用 async 和 await 正确处理

c# - 自动映射时可以展平对象的一部分

c# - 了解 csproj 程序集引用

android - 无法在 Android 中打开数据库(预创建)