原文: http://zetcode.com/db/sqlitecsharp/intro/

在 SQLite C# 教程的第一章中,我们将提供必要的定义。 我们将展示如何安装 Mono。 本教程中的所有示例都将在 Mono 上运行。 稍后,我们创建第一个工作示例。

关于 SQLite 数据库

SQLite 是嵌入式关系数据库引擎。 它的开发者称其为自包含,无服务器,零配置和事务型 SQL 数据库引擎。 它非常受欢迎,当今全球有数亿本使用。 SQLite 用于 Solaris 10 和 Mac OS 操作系统,iPhone 或 Skype。 Qt4 库对 SQLite 以及 Python 或 PHP 语言提供了内置支持。 许多流行的应用内部都使用 SQLite,例如 Firefox 或 Amarok。

  1. $ sudo apt-get install sqlite3

如果尚未安装sqlite3库,则需要安装它。

SQLite 附带sqlite3命令行工具。 它可用于对数据库发出 SQL 命令。 现在,我们将使用sqlite3命令行工具创建一个新数据库。

  1. $ sqlite3 test.db
  2. SQLite version 3.6.22
  3. Enter ".help" for instructions
  4. Enter SQL statements terminated with a ";"

我们为sqlite3工具提供了一个参数。 test.db是数据库名称。 它是我们磁盘上的单个文件。 如果存在,则将其打开。 如果不是,则创建它。

  1. sqlite> .tables
  2. sqlite> .exit
  3. $ ls
  4. test.db

.tables命令提供了test.db数据库中的表列表。 当前没有表。 .exit命令终止sqlite3命令行工具的交互式会话。 ls Unix 命令显示当前工作目录的内容。 我们可以看到test.db文件。 所有数据将存储在该单个文件中。

Mono

Mono 是基于 C# 和公共语言运行时的 ECMA 标准的 Microsoft .NET Framework 的开源实现。 在本教程中,我们需要安装 Mono 才能编译和运行示例。

可以从 Linux 发行版的包中安装 Mono,也可以从源代码中安装 Mono,以获得更多最新版本。

  1. $ bunzip2 mono-2.10.8.tar.bz2
  2. $ tar -xf mono-2.10.8.tar
  3. $ cd mono-2.10.8/
  4. $ ./configure
  5. $ make
  6. $ sudo make install

我们从 Mono 网站下载mono-2.10.8.tar.bz2 tarball。 解压缩,构建并安装库。 我们安装了 Mono 运行时,C# 语言和 SQLite C# 数据适配器。

  1. $ bunzip2 libgdiplus-2.10.9.tar.bz2
  2. $ tar -xf libgdiplus-2.10.9.tar
  3. $ cd libgdiplus-2.10.9/
  4. $ ./configure
  5. $ make
  6. $ sudo make install

对于带有 Winforms 控件的示例,我们还需要libgdiplus库。 它位于单独的文件中。 我们构建并安装它。

  1. $ sudo ldconfig
  2. $ ldconfig -p | grep libgdiplus
  3. libgdiplus.so.0 (libc6) => /usr/local/lib/libgdiplus.so.0
  4. libgdiplus.so (libc6) => /usr/local/lib/libgdiplus.so

我们还运行ldconfig工具来更新动态库的数据库。 ldconfig扫描正在运行的系统,并设置用于加载共享库的符号链接。

Mono.Data.Sqlite程序集包含 SQLite 数据库的 ADO.NET 数据供应器。 它用 C# 编写,并且可用于所有 CLI 语言:C# ,Visual Basic,Boo 等。

  1. $ ls /usr/local/lib/mono/4.0/Mono.Data.Sqlite.dll
  2. /usr/local/lib/mono/4.0/Mono.Data.Sqlite.dll

从技术角度来看,我们需要一个 DLL。 在我们的系统上,它位于上述路径下。 (实际上,以上是指向 DLL 的软链接,该 DLL 位于gac子目录中。)

ADO.NET

ADO.NET是 .NET 框架的重要组成部分。 该规范统一了对关系数据库,XML 文件和其他应用数据的访问。 从程序员的角度来看,它是一组与数据库和其他数据源一起使用的库和类。 Mono.Data.SQLite是 SQLite 数据库的 ADO.NET 规范的实现。 它是用 C# 语言编写的驱动程序,可用于所有.NET 语言。

SqliteConnectionSqliteCommandSqliteDataReaderSqliteDataAdapter是.NET 数据供应器模型的核心元素。 SqliteConnection创建到特定数据源的连接。 SqliteCommand对象针对数据源执行一条 SQL 语句。 SqliteDataReader从数据源读取数据流。 SqliteDataAdapterDataSet和数据源之间的中介。 它填充DataSet并解析数据源的更新。

DataSet对象用于大量数据的离线工作。 它是一种断开连接的数据表示形式,可以保存来自各种不同来源的数据。 SqliteDataReaderDataSet都用于处理数据。 它们在不同的情况下使用。 如果只需要读取查询结果,则SqliteDataReader是更好的选择。 如果我们需要更广泛的数据处理,或者要将 Winforms 控件绑定到数据库表,则首选DataSet

SQLite 版本

如果是第一个程序,我们将检查 SQLite 数据库的版本。

  1. using System;
  2. using Mono.Data.Sqlite;
  3. public class Example
  4. {
  5. static void Main()
  6. {
  7. string cs = "Data Source=:memory:";
  8. SqliteConnection con = null;
  9. SqliteCommand cmd = null;
  10. try
  11. {
  12. con = new SqliteConnection(cs);
  13. con.Open();
  14. string stm = "SELECT SQLITE_VERSION()";
  15. cmd = new SqliteCommand(stm, con);
  16. string version = Convert.ToString(cmd.ExecuteScalar());
  17. Console.WriteLine("SQLite version : {0}", version);
  18. } catch (SqliteException ex)
  19. {
  20. Console.WriteLine("Error: {0}", ex.ToString());
  21. } finally
  22. {
  23. if (cmd != null)
  24. {
  25. cmd.Dispose();
  26. }
  27. if (con != null)
  28. {
  29. try
  30. {
  31. con.Close();
  32. } catch (SqliteException ex)
  33. {
  34. Console.WriteLine("Closing connection failed.");
  35. Console.WriteLine("Error: {0}", ex.ToString());
  36. } finally
  37. {
  38. con.Dispose();
  39. }
  40. }
  41. }
  42. }
  43. }

我们连接到内存数据库并选择一个 SQLite 版本。

  1. using Mono.Data.Sqlite;

Mono.Data.SqliteClient程序集包含 SQLite 数据库引擎的 ADO.NET 数据供应器。 我们导入 SQLite 数据供应器的元素。

  1. string cs = "Data Source=:memory:";

这是连接字符串。 数据提供者使用它来建立与数据库的连接。 我们创建一个内存数据库。

  1. con = new SqliteConnection(cs);

创建一个SqliteConnection对象。 该对象用于打开与数据库的连接。

  1. con.Open();

这行打开数据库连接。

  1. string stm = "SELECT SQLITE_VERSION()";

这是SQL SELECT语句。 它返回数据库的版本。 SQLITE_VERSION()是内置的 SQLite 函数。

  1. SqliteCommand cmd = new SqliteCommand(stm, con);

SqliteCommand是一个对象,用于在数据库上执行查询。 参数是 SQL 语句和连接对象。

  1. string version = Convert.ToString(cmd.ExecuteScalar());

有些查询仅返回标量值。 在我们的例子中,我们需要一个简单的字符串来指定数据库的版本。 在这种情况下使用ExecuteScalar()。 我们避免了使用更复杂的对象的开销。

  1. Console.WriteLine("SQLite version : {0}", version);

数据库的版本将打印到控制台。

  1. } catch (SqliteException ex)
  2. {
  3. Console.WriteLine("Error: {0}", ex.ToString());

如果发生异常,我们将错误消息打印到控制台。

  1. } finally
  2. {
  3. if (cmd != null)
  4. {
  5. cmd.Dispose();
  6. }

SqliteCommand类实现IDisposable接口。 因此,必须对其进行明确处理。

  1. if (con != null)
  2. {
  3. try
  4. {
  5. con.Close();
  6. } catch (SqliteException ex)
  7. {
  8. Console.WriteLine("Closing connection failed.");
  9. Console.WriteLine("Error: {0}", ex.ToString());
  10. } finally
  11. {
  12. con.Dispose();
  13. }
  14. }

关闭连接可能会引发另一个异常。 我们处理这种情况。

  1. $ dmcs version.cs -r:Mono.Data.Sqlite.dll

我们汇编示例。 提供了 SQLite 数据供应器 DLL 的路径。

  1. $ mono ./version.exe
  2. SQLite version : 3.7.7

这是我们系统上程序的输出。

using语句

C# 语言实现垃圾回收。 这是一个自动释放不再需要的对象的过程。 该过程是不确定的。 我们不能确定 CLR(公共语言运行时)何时决定释放资源。 对于有限的资源,例如文件句柄或网络连接,最好尽快释放它们。 使用using语句,程序员可以控制何时释放资源。 当程序超出了using块时,到达其末尾或引发异常,则资源被释放。

在内部,using语句被转换为tryfinally块,在finally块中调用了Dispose()。 请注意,您可能更喜欢使用trycatchfinally块,而不是using语句。 特别是,如果您想显式地利用catch块。 在本教程中,我们选择了 using 语句。 主要是因为代码较短。

通常,当我们使用IDisposable对象时,应在using语句中声明并实例化它。 (或在finally块中调用Dispose()方法。)对于 SQLite ADO.NET 驱动程序,我们对SqliteConnectionSqliteCommandSqliteDataReaderSqliteCommandBuilderSqliteDataAdapter类使用using语句。 我们不必将其用于DataSetDataTable类。 他们可以留给垃圾收集器。

  1. using System;
  2. using Mono.Data.Sqlite;
  3. public class Example
  4. {
  5. static void Main()
  6. {
  7. string cs = "URI=file:test.db";
  8. using (SqliteConnection con = new SqliteConnection(cs))
  9. {
  10. con.Open();
  11. using (SqliteCommand cmd = new SqliteCommand(con))
  12. {
  13. cmd.CommandText = "SELECT SQLITE_VERSION()";
  14. string version = Convert.ToString(cmd.ExecuteScalar());
  15. Console.WriteLine("SQLite version : {0}", version);
  16. }
  17. con.Close();
  18. }
  19. }
  20. }

我们有同样的例子。 这次我们实现了using关键字。

  1. using (SqliteConnection con = new SqliteConnection(cs))
  2. {
  3. con.Open();
  4. using (SqliteCommand cmd = new SqliteCommand(con))

SqliteConnectionSqliteCommand都实现IDisposable接口。 因此,它们用using关键字包装。

创建并填充表

接下来,我们将创建一个数据库表并用数据填充它。

  1. using System;
  2. using Mono.Data.Sqlite;
  3. public class Example
  4. {
  5. static void Main()
  6. {
  7. string cs = "URI=file:test.db";
  8. using ( SqliteConnection con = new SqliteConnection(cs))
  9. {
  10. con.Open();
  11. using (SqliteCommand cmd = new SqliteCommand(con))
  12. {
  13. cmd.CommandText = "DROP TABLE IF EXISTS Cars";
  14. cmd.ExecuteNonQuery();
  15. cmd.CommandText = @"CREATE TABLE Cars(Id INTEGER PRIMARY KEY,
  16. Name TEXT, Price INT)";
  17. cmd.ExecuteNonQuery();
  18. cmd.CommandText = "INSERT INTO Cars VALUES(1,'Audi',52642)";
  19. cmd.ExecuteNonQuery();
  20. cmd.CommandText = "INSERT INTO Cars VALUES(2,'Mercedes',57127)";
  21. cmd.ExecuteNonQuery();
  22. cmd.CommandText = "INSERT INTO Cars VALUES(3,'Skoda',9000)";
  23. cmd.ExecuteNonQuery();
  24. cmd.CommandText = "INSERT INTO Cars VALUES(4,'Volvo',29000)";
  25. cmd.ExecuteNonQuery();
  26. cmd.CommandText = "INSERT INTO Cars VALUES(5,'Bentley',350000)";
  27. cmd.ExecuteNonQuery();
  28. cmd.CommandText = "INSERT INTO Cars VALUES(6,'Citroen',21000)";
  29. cmd.ExecuteNonQuery();
  30. cmd.CommandText = "INSERT INTO Cars VALUES(7,'Hummer',41400)";
  31. cmd.ExecuteNonQuery();
  32. cmd.CommandText = "INSERT INTO Cars VALUES(8,'Volkswagen',21600)";
  33. cmd.ExecuteNonQuery();
  34. }
  35. con.Close();
  36. }
  37. }
  38. }

在上面的代码示例中,我们创建具有 8 行的Cars表。

  1. cmd.CommandText = "DROP TABLE IF EXISTS Cars";
  2. cmd.ExecuteNonQuery();

首先,如果该表已经存在,则将其删除。 如果我们不想要结果集,例如对于DROPINSERTDELETE语句,可以使用ExecuteNonQuery()方法。

  1. cmd.CommandText = @"CREATE TABLE Cars(Id INTEGER PRIMARY KEY,
  2. Name TEXT, Price INT)";
  3. cmd.ExecuteNonQuery();

Cars表已创建。 INTEGER PRIMARY KEY列在 SQLite 中自动增加。

  1. cmd.CommandText = "INSERT INTO Cars VALUES(1,'Audi',52642)";
  2. cmd.ExecuteNonQuery();
  3. cmd.CommandText = "INSERT INTO Cars VALUES(2,'Mercedes',57127)";
  4. cmd.ExecuteNonQuery();

我们在表中插入两行。

  1. sqlite> .mode column
  2. sqlite> .headers on

sqlite3命令行工具中,我们修改了数据在控制台中的显示方式。 我们使用列模式并打开标题。

  1. sqlite> SELECT * FROM Cars;
  2. Id Name Price
  3. ---------- ---------- ----------
  4. 1 Audi 52642
  5. 2 Mercedes 57127
  6. 3 Skoda 9000
  7. 4 Volvo 29000
  8. 5 Bentley 350000
  9. 6 Citroen 21000
  10. 7 Hummer 41400
  11. 8 Volkswagen 21600

我们验证数据。 Cars表已成功创建。

预备语句

现在,我们将以预备语句来关注自己。 在编写预备语句时,我们使用占位符,而不是直接将值写入语句中。 预准备的语句可提高安全性和性能。

  1. using System;
  2. using Mono.Data.Sqlite;
  3. public class Example
  4. {
  5. static void Main()
  6. {
  7. string cs = "URI=file:test.db";
  8. using(SqliteConnection con = new SqliteConnection(cs))
  9. {
  10. con.Open();
  11. using (SqliteCommand cmd = new SqliteCommand(con))
  12. {
  13. cmd.CommandText = "INSERT INTO Cars(Name, Price) VALUES(@Name, @Price)";
  14. cmd.Prepare();
  15. cmd.Parameters.AddWithValue("@Name", "BMW");
  16. cmd.Parameters.AddWithValue("@Price", 36600);
  17. cmd.ExecuteNonQuery();
  18. }
  19. con.Close();
  20. }
  21. }
  22. }

我们向Cars表添加一行。 我们使用参数化命令。

  1. cmd.CommandText = "INSERT INTO Cars(Name, Price) VALUES(@Name, @Price)";
  2. cmd.Prepare();

在这里,我们创建一个预备语句。 在编写预备语句时,我们使用占位符,而不是直接将值写入语句中。 预备语句更快,并且可以防止 SQL 注入攻击。 @Name@Price是占位符,稍后将填充。

  1. cmd.Parameters.AddWithValue("@Name", "BMW");
  2. cmd.Parameters.AddWithValue("@Price", 36600);

值绑定到占位符。

  1. cmd.ExecuteNonQuery();

执行预备语句。 当我们不希望返回任何数据时,我们使用SqliteCommand对象的ExecuteNonQuery()方法。

  1. $ mono prepared.exe
  2. sqlite> SELECT * FROM Cars;
  3. Id Name Price
  4. ---------- ---------- ----------
  5. 1 Audi 52642
  6. 2 Mercedes 57127
  7. 3 Skoda 9000
  8. 4 Volvo 29000
  9. 5 Bentley 350000
  10. 6 Citroen 21000
  11. 7 Hummer 41400
  12. 8 Volkswagen 21600
  13. 9 BMW 36600

我们有一辆新车插入表。

数据来源

已咨询 MSDN(Microsoft 开发者网络)来创建本教程。 该网站有几种定义。

这是 SQLite C# 教程的介绍性章节。