ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

在.NET WinForms中创建SQLite数据库

在.NET WinForms中创建SQLite数据库

文章目录

  • 1、前置环境
  • 2、数据的建立
  • 3、数据库的访问
  • 4、验证与查看数据
  • 5、常见问题
  • 6、要点汇总

1、前置环境

安装 SQLite 软件包:点击工具栏工具>NuGet 包管理器>程序包管理器控制台:

在控制台输入下载命令:

Install-Package System.Data.SQLite.Core

说明:

  • System.Data.SQLite.Core是 .NET Framework / WinForms 项目的首选包,安装后自动携带 32/64 位原生引擎SQLite.Interop.dll。
  • 也可以走「工具 > NuGet 包管理器 > 管理解决方案的 NuGet 程序包」图形界面搜索安装,效果相同。
  • 不需要同时安装Microsoft.Data.Sqlite、SQLitePCLRaw.*,两套驱动混装会导致无法加载 DLL"e_sqlite3"报错。

2、数据的建立

核心思路:SQLite 的"建库"就是创建一个文件,连接串指向的文件不存在时会自动创建;表结构用CREATE TABLE IF NOT EXISTS在程序启动时执行一次,重复运行不会报错也不会清数据。

具体步骤:

(1)新建一个类文件Db.cs,引入命名空间:

using System.Data.SQLite; using System.IO; using System.Windows.Forms; // 用到 Application.StartupPath

(2)定义数据库文件路径与连接字符串:

// 数据库文件放在程序运行目录(bin\Debug)下 private static readonly string DbPath = Path.Combine(Application.StartupPath, "myapp.db"); private static readonly string ConnStr = "Data Source=" + DbPath + ";Version=3;";

Data Source指向.db文件路径;Version=3表示使用 SQLite 3 协议。

(3)封装获取连接的方法(用完即关,SQLite 连接开销极小):

public static SQLiteConnection GetConnection() { var conn = new SQLiteConnection(ConnStr); conn.Open(); return conn; }

(4)编写初始化方法,执行建表 SQL:

public static void Init() { using (var conn = GetConnection()) using (var cmd = conn.CreateCommand()) { cmd.CommandText = @"CREATE TABLE IF NOT EXISTS ..."; cmd.ExecuteNonQuery(); } }

(5)在程序入口最先调用一次Init()(Program.cs):

[STAThread] static void Main() { Db.Init(); // 建库 + 建表,必须放在窗体启动之前 Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new For()); }(6)运行程序,`bin\Debug\` 目录下出现 `myapp.db`,建库完成。

整体代码参考:

public static class Db { // 数据库文件放在程序目录下 private static readonly string DbPath = Path.Combine(Application.StartupPath, "myapp.db"); private static readonly string ConnStr = "Data Source=" + DbPath + ";Version=3;"; // 获取连接(每次操作用完即关,SQLite 开销很小) public static SQLiteConnection GetConnection() { var conn = new SQLiteConnection(ConnStr); conn.Open(); return conn; } // 程序启动时调用一次:建库 + 建表 public static void Init() { using (var conn = GetConnection()) using (var cmd = conn.CreateCommand()) { cmd.CommandText = @" CREATE TABLE IF NOT EXISTS Users ( Id INTEGER PRIMARY KEY AUTOINCREMENT, UserName TEXT NOT NULL UNIQUE, Password TEXT NOT NULL, Phone TEXT, CreatedAt TEXT DEFAULT (datetime('now','localtime')) ); CREATE TABLE IF NOT EXISTS Orders ( Id INTEGER PRIMARY KEY AUTOINCREMENT, UserId INTEGER NOT NULL, Amount REAL NOT NULL, Status TEXT DEFAULT '待处理', FOREIGN KEY (UserId) REFERENCES Users(Id) );"; cmd.ExecuteNonQuery(); } } }

3、数据库的访问

固定套路:Db.GetConnection()拿连接 → 建Command→ 写 SQL(参数化)→ 执行 →using自动释放。

(1)查询:填充到 DataGridView

private void LoadUsers() { using (var conn = Db.GetConnection()) using (var da = new SQLiteDataAdapter( "SELECT Id AS 编号, UserName AS 用户名, Phone AS 电话, CreatedAt AS 创建时间 FROM Users ORDER BY Id", conn)) { var dt = new DataTable(); da.Fill(dt); // 执行查询并填充 dgvUsers.DataSource = dt; // 绑定显示 } }

(2)插入:注意@参数占位,禁止字符串拼接

using (var conn = Db.GetConnection()) using (var cmd = conn.CreateCommand()) { cmd.CommandText = "INSERT INTO Users(UserName, Password, Phone) VALUES(@u, @p, @ph)"; cmd.Parameters.AddWithValue("@u", txtName.Text.Trim()); cmd.Parameters.AddWithValue("@p", "123456"); cmd.Parameters.AddWithValue("@ph", txtPhone.Text.Trim()); int rows = cmd.ExecuteNonQuery(); // 返回受影响行数 }

(3)修改:

using (var conn = Db.GetConnection()) using (var cmd = conn.CreateCommand()) { cmd.CommandText = "UPDATE Users SET Phone=@ph WHERE Id=@id"; cmd.Parameters.AddWithValue("@ph", txtPhone.Text.Trim()); cmd.Parameters.AddWithValue("@id", id); cmd.ExecuteNonQuery(); }

(4)删除:

using (var conn = Db.GetConnection()) using (var cmd = conn.CreateCommand()) { cmd.CommandText = "DELETE FROM Users WHERE Id=@id"; cmd.Parameters.AddWithValue("@id", id); cmd.ExecuteNonQuery(); }

(5)查询单个值(登录校验、统计等):

using (var conn = Db.GetConnection()) using (var cmd = conn.CreateCommand()) { cmd.CommandText = "SELECT COUNT(*) FROM Users WHERE UserName=@u AND Password=@p"; cmd.Parameters.AddWithValue("@u", txtName.Text.Trim()); cmd.Parameters.AddWithValue("@p", txtPwd.Text.Trim()); long count = (long)cmd.ExecuteScalar(); // 返回第一行第一列 if (count > 0) MessageBox.Show("登录成功"); }

三种执行方式的区别:

执行方法适用场景返回值
ExecuteNonQuery()INSERT / UPDATE / DELETE、建表受影响行数
ExecuteScalar()COUNT / MAX / 取单个字段第一行第一列(object,需强转)
ExecuteReader()/SQLiteDataAdapter.Fill()SELECT 多行多列读取器 / DataTable

4、验证与查看数据

.db文件不能用记事本或 Visual Studio 直接打开(是二进制文件,打开是乱码),需用专用工具:

  • DB Browser for SQLite(免费开源,https://sqlitebrowser.org):打开bin\Debug\myapp.db,「数据库结构」页看表、「浏览数据」页看记录。
  • 查看前建议先关闭程序,避免 SQLite 文件锁导致database is locked。

5、常见问题

(1)System.DllNotFoundException:无法加载 DLL"e_sqlite3"

原因是项目里混装了两套 SQLite 驱动,或原生 DLL 未复制到输出目录。处理:卸载全部 SQLite 相关包后只装一个。

Uninstall-PackageMicrosoft.Data.Sqlite-ForceUninstall-PackageSQLitePCLRaw.bundle_e_sqlite3-ForceUninstall-PackageSQLitePCLRaw.core-ForceInstall-PackageSystem.Data.SQLite.Core

生成后确认bin\Debug\x86\SQLite.Interop.dll与bin\Debug\x64\SQLite.Interop.dll均存在。

(2)no such table: Users

Db.Init()没有被调用,或调用晚于查询。确认它在Program.Main()的第一行。

(3)database is locked

另一个进程(如 DB Browser)占用了文件,或连接未关闭。坚持用using包裹连接。

(4)数据被清空/表丢失

不要用CREATE TABLE(无IF NOT EXISTS)加DROP TABLE的组合做初始化;也不要把bin\Debug\myapp.db当作"临时文件"删除——它就是正式数据。

6、要点汇总

  1. SQLite 是嵌入式数据库,无需安装 SQL Server、MySQL 等数据库服务,NuGet 装包即可。
  2. 建库 = 建文件,连接串指向的.db不存在时自动创建。
  3. 建表语句必须带IF NOT EXISTS,保证程序重复启动安全。
  4. SQL 值一律用@参数+AddWithValue,防注入、防单引号报错。
  5. 连接一律using包裹,用完即关。
  6. 数据库文件随程序发布,拷到任何 Windows 电脑可直接运行,无需配环境。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进