1.引言
项目中需要用到一个本地文件数据库,而且最好要使用Code First模式,于是就想到了Sqlite。对于个人来说也第一次使用sqlite的Code First模式,在这个过程中踩了不少的坑,因此写了这篇文章与君分享,文中有误可以当面指出,不必留情。
2.Code First
抄了一段话:SQLite 是一个软件库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite 是在世界上最广泛部署的 SQL 数据库引擎。SQLite 源代码不受版权限制。使用code frist创建sqlite数据库,只需要按照如下简单的几个步骤即可:
(1)新类库SqliteDB,建Model【Programmer,ProjectManager】,在类库中引入Nuget包 SQLite.CodeFirst。
(2)继承一个Context类SqliteDbContext,由于只是简单的测试,所以没有涉及到复杂的设置。
public class SqliteDbContext:DbContext
{
public SqliteDbContext():base("name = sqlite")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Programmer>().ToTable("Programmer").HasKey(p => p.ID);
modelBuilder.Entity<ProjectManager>().ToTable("ProjectManager").HasKey(p => p.ID);
Database.SetInitializer(new SqliteCreateDatabaseIfNotExists<SqliteDbContext>(modelBuilder));
}
public virtual DbSet<Programmer> Programmers { get; set; }
public virtual DbSet<ProjectManager> ProjectManager { get; set; }
}
注意,这里的构造函数父类中传入的参数“name = sqlite”,其中“sqlite”是连接字符串的key值。
(3)新建测试类库,引入Nuget包 System.Data.SQLite,System.Data.SQLite是SQLite的加强版,它可以无需.NET Framework支持,由于它内部包含了一个ADO.NET 2.0引擎,所以.NET开发人员可以利用System.Data.SQLite方便地开发.NET程序,实现sqlite数据库的增删改查。
(4)修改连接配置,实现增删改查代码
注意上面红框的配置文件,需要将原来的【System.Data.SQLite.EF6】改为【System.Data.SQLite】,然后新增连接字符串(这个连接字符串在下面将会为你详解)
<add name="sqlite" connectionString="data source=D:\\SqliteDB\\sqlite.db;BinaryGUID=False" providerName="System.Data.SQLite.EF6" />
上面的简单的几步即可完成sqlite的数据库code first模式,看看结果:
是不是觉得很简单,小儿科啊,我一开始也觉得很简单,直到我在坑中陷了3天,其中还有些地方需要注意的,这也是写本文的初衷,且容我慢慢道来~~~
3.踩过的那些坑
(1)坑一:配置文件
引入的【System.Data.SQLite】包后生成的配置文件是直接使用是有问题的,需要按照步骤四中去掉后面的“.EF6”;连接字符串中“providerName=”System.Data.SQLite.EF6””,后面的“.EF6”需要加上否则也报错,至于为什么非得这么配,现在还没有弄明白,这些是我在网上找到的,如果有大神知道,希望当面指教。
(2)坑二:GUID的存储
sqlite是Typelessness(无类型). 对! SQLite是无类型的. 这意味着你可以保存任何类型的数据到你所想要保存的任何表的任何列中,对于SQLite来说对字段不指定类型是完全有效的。C#中的GUID在sqlite中默认是以二进制存储的,这也就是为什么你用UI工具或者sqlite3.exe打开的时候发现是乱码的原因。这就麻烦了,查询的时候要使用GUID比对怎么办?通常的做法就是,ToByteArray()方法,然后再转换成16进制字符串,原因是GUID的文本表示和二进制的存储顺序并不是完全一样。总觉得这样做很繁琐,解决的方案一:不要用GUID咯,规避这个问题,个人认为这是一个很好的解决办法,但是有的时候如果非得使用GUID呢?解决方案二:在连接字符串中加入【BinaryGUID=False”】,指定GUID按照字符串存储,也就是说Model中的字段类型依然是GUID,但是数据中却存的是text。
![这里写图片描述]
(3)坑三:未能找到表xxx
运行代码生成数据库sqlite.db,执行新增,报错“logic error:no such table xxx”,打开数据库看发现表xxx在里面,好神奇哦,这特么坑了我两天的时间,巨坑啊。上面的那个简单的测试代码中并没有出现这种问题,问题是在实际项目中报出来的,这里不便贴出代码,只能口述了,在实际项目中连接字符串data source采用的是相对路径,即相对与.exe的路径,运行生成的不仅会在你连接字符串中指定的相对位置中生成一份文件数据库,而且还会在另外一个地方生成一份数据库,这个地方我现在不确定,不能乱说(求大神指教),但是肯定存在,这个数据库是空的,新增的数据的时候使用的是这个数据库,因此才有了上面的错误:找不到表。解决方案:避开相对路径,大不了部署的时候手动修改数据库配置,这是我目前看到的最好的方法。
(4)坑四:未能加载【SQLite.Interop.dll】
一切都准备就绪,满心欢喜,这下总特么可以了吧,报错“Unable to load DLL ‘SQLite.Interop.dll’”,什么鬼啊,查资料,下载SQLite.Interop.dll,添加引用,报错,无法添加引用,注册一下,注册失败,疯了,在找资料,原来这个动态链接库不是C#开发的,不能添加,只能直接复制到exe同级目录咯,正解,总算运行成功了。
4.总结
不断的采坑,痛苦挣扎,不断的找资料,解决问题,满心欢喜,编程之乐,乐在其中啊。