作者:梁利锋

873天前 (阅读:1713)

最近很想把 DbEntry.Net 的单元测试改成内存数据库的方式,而且最好是纯C#版,这样就可以在任意的环境(win/linux/macos)运行。本来如果实在没有的话,也想过自己实现一个。不过,最终还是找到了一个SQLite的纯C#版本,通过修改实现了这个目的。

我从 CsharpSQLite fork了一个版本进行修改。这个项目最初的源代码应该是来自 Google Code。更多的信息可以参考 InfoQ

我称我添加的这个功能为真实的内存数据库。真实的意思是,它的各种行为方式,和文件型数据库一样。

SQLite本身也是支持内存数据库的,只是它支持的方式跟文件型不同。它的内存数据库会在Connetion创建时创建,而在Connection 关闭时销毁。而且所有操作都需要使用这个Connection,而如果另外的线程要使用这个Connection却会造成一个异常。

实现我所谓真实的内存数据库的方式是,增加一个选项,如果选择内存数据库,则把所有文件访问函数替换成文件访问函数。所有的结果会被保存在一个Dictionary\中,它使用文件名作为Key,而文件内容作为Value。所以我们可以多次访问同一个名字的内存数据库。而且我们可以通过一个真实的文件内容对这个内存数据库进行初始化,而不是使用一组SQL语句。所有这些,导致它的速度大大高于文件型数据库。

我在DbEntry.Net的单元测试中测试了它。运行所有的单元测试,文件型数据库会耗费50秒左右,而内存数据库只需要10秒所有。另外内存数据库也稍微快于在内存盘上使用文件型数据库。

下面的代码是单元测试的基类,其中被注释掉的代码是使用文件型数据库的代码。

public class DataTestBase : SqlTestBase
{
    private const string FileName = "UnitTest.db";
    private static readonly string TestFilePath = "/Volumes/RamDisk/" + FileName;
    private static readonly byte[] TestFileBuffer = ResourceHelper.ReadAll(typeof(DataTestBase), FileName);
    protected override void OnSetUp()
    {
        /*
        File.Delete(TestFilePath);
        using (Stream s = new FileStream(TestFilePath, FileMode.Create))
        {
            s.Write(TestFileBuffer, 0, TestFileBuffer.Length);
        }
        */
        System.Data.SQLite.TypeHolder.Type = StreamType.Memory;
        var bs = new byte[TestFileBuffer.Length];
        TestFileBuffer.CopyTo(bs, 0);
        System.Data.SQLite.MemFileStream.Files [TestFilePath] = bs;
    }
    protected override void OnTearDown()
    {
        System.Data.SQLite.MemStreamHandler.Instance.Delete (TestFilePath);
        //File.Delete(TestFilePath);
    }
}

这个新功能的源代码可以在 Github 找到。