使用 SqlBulkCopy 连接到 SQLite 数据库

Posted

技术标签:

【中文标题】使用 SqlBulkCopy 连接到 SQLite 数据库【英文标题】:Connecting to a SQLLite db with SqlBulkCopy 【发布时间】:2017-11-08 21:42:57 【问题描述】:

我正在用 c# 为一个函数编写单元测试,该函数负责使用 System.Data.SqlClient.SqlBulkCopy 将 DataTable 复制到数据库服务器。

我使用 SQLLite 进行单元测试,并希望使用 SqlBulkCopy 连接到内存数据库中的 SQLLite,然后将该测试数据批量复制到 SQLLite 数据库中。

但是,我似乎无法正确获取连接字符串。

我最初尝试过

var bcp = new SqlBulkCopy("FullUri=file::memory:?cache=shared")

然后

var bcp = new SqlBulkCopy("Data Source=:memory:;Cache=Shared")

哪个不认识Cache 所以我尝试了

var bcp = new SqlBulkCopy("Data Source=:memory:")

出于绝望,只是在尝试连接数据库时超时。

我想在这里完成的事情可能吗?如果是,有人可以帮我处理连接字符串吗?

【问题讨论】:

【参考方案1】:

您不能将SqlBulkCopy 用于 SQLite。 SqlBulkCopy 已为 SQL Server 完成。

通常,显着提高 SQLite 性能的诀窍是确保使用事务。


免责声明:我是.NET Bulk Operations的所有者

此库不是免费的,但允许您轻松执行和自定义所有批量操作:

批量插入 批量删除 批量更新 批量合并

例子

// Easy to use
var bulk = new BulkOperation(connection);
bulk.BulkInsert(dt);
bulk.BulkUpdate(dt);
bulk.BulkDelete(dt);
bulk.BulkMerge(dt);

// Easy to customize
var bulk = new BulkOperation<Customer>(connection);
bulk.BatchSize = 1000;
bulk.ColumnInputExpression = c => new  c.Name,  c.FirstName ;
bulk.ColumnOutputExpression = c => c.CustomerID;
bulk.ColumnPrimaryKeyExpression = c => c.Code;
bulk.BulkMerge(customers);

编辑:回复评论

我想从 SQLite 加载一个数据表,然后将其“批量复制”到其他数据库中

这种情况是可能的,但需要2个连接

DbConnection sourceConnection = // connection from the source
DbConnection destinationConnection = // connection from the destination

// Fill the DataTable using the sourceConnection
dt = ...;

// BulkInsert using the destinationConnection
var bulk = new BulkOperation(destinationConnection);
bulk.BulkInsert(dt);

【讨论】:

我想从 SQLite 加载一个数据表,然后在其他数据库(mysql、Oracle、Postgre 和 SQL Server)中“批量复制”它。我认为 BulkOperation 是可能的,但代码示例会有很大帮助 我已尝试使用 Z.BulkOperations NuGet 包将 100,000 条简单记录(Id INTEGER、Name TEXT)插入 SQLite 数据库。在我的机器上使用 BulkOperation.BulkInsert(DataTable 或实体)比通过 SQLiteCommand 手动插入记录慢大约 2 倍。这太糟糕了,因为我希望有一些解决方案可以让我比使用 SQLiteCommand 更快地将记录批量插入 SQLite 数据库。 您好,David,如果您可以在此处提供可运行的解决方案:info@zzzprojects.com,我们将很乐意查看它并找出您的情况为什么会变慢。【参考方案2】:

答案是您无法将 SqlBulkCopy 连接到 SQLite 实例。

我为解决我的问题(对使用 SqlBulkCopy 的代码的一部分进行单元测试)所做的工作是围绕 SqlBulkCopy 创建一个包装器,该包装器是使用 SqlBulkCopy 实现的,用于生产代码,并在测试代码中使用模拟批量复制。有效解耦对 SqlBulkCopy 本身的依赖。

具体来说,我创建了

public interface IBulkCopy : IDisposable 
    string DestinationTableName  get; set; 
    void CreateColumnMapping(string from, string to);
    Task WriteToServerAsync(DataTable dt);

然后,我将其实现为

public class SQLBulkCopy : IBulkCopy  

    private SqlBulkCopy _sbc;

    public string DestinationTableName 
        get  return _sbc.DestinationTableName; 
        set  _sbc.DestinationTableName = value; 
    

    public SQLBulkCopy(IDBContext ctx)  
        _sbc = new SqlBulkCopy((SqlConnection)ctx.GetConnection());
    

    public void CreateColumnMapping(string from, string to) 
        _sbc.ColumnMappings.Add(new SqlBulkCopyColumnMapping(from, to));
    

    public Task WriteToServerAsync(DataTable dt) 
        return _sbc.WriteToServerAsync(dt);
    


在我的测试实用程序中,我只用插入模拟了“批量复制”:

class MockBulkCopy : IBulkCopy 

    private IDBContext _context;

    public MockBulkCopyHelper(IDBContext context) 
        _context = context;
    

    public string DestinationTableName  get; set; 

    public void CreateColumnMapping(string fromName, string toName) 
        //We don't need a column mapping for raw SQL Insert statements.
        return;
    

    public virtual Task WriteToServerAsync(DataTable dt) 
        return Task.Run(() => 
            using (var cn = _context.GetConnection()) 
                using (var cmd = cn.CreateCommand()) 
                    cmd.CommandText = $"INSERT INTO DestinationTableName(GetCsvColumnList(dt)) VALUES GetCsvValueList(dt)";
                    cmd.ExecuteNonQuery();
                
            
        );
    

GetCsvColumnListGetCsvValueList 我是作为辅助函数实现的。

【讨论】:

那么你在这里实际测试了什么?我相信它只测试所有列映射是否正确完成。如果是这种情况,您可以将该功能提取到一个单独的类中并为此编写单元测试,而无需单独使用批量复制操作类。这会更容易,IMO。 是的,这很好。这不是测试驱动的开发,这里的想法只是为了编写一些单元测试而不修改它为了截止日期而测试的代码。理想情况下我会走你建议的路线,但我正在使用的代码与 sbc 紧密耦合,所以我必须模拟这个变通方法。

以上是关于使用 SqlBulkCopy 连接到 SQLite 数据库的主要内容,如果未能解决你的问题,请参考以下文章

连接到数据源 SQLite 失败

QSqlDatabase 并连接到 .sqlite 文件

PyCharm 无法连接到 SQLite:SQLITE_BUSY,(数据库已锁定)

如何将 SQlite 数据库连接到 devcpp? [关闭]

sqlite3:连接到云中的数据库(S3)

Symfony2 无法连接到 sqlite