VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > c#编程 >
  • SQLite本地数据库——C#编写桌面应用数据存储

第一部分:C#基础入门
SQLite本地数据库——桌面应用数据存储
实例介绍
SQLite是轻量级文件型数据库的代表,完美适配桌面应用(如WPF、WinForms、控制台):无需安装服务、单文件存储、跨平台支持、ACID兼容。本节通过“个人待办事项管理”场景,带你vb.net教程C#教程python教程SQL教程access 2010教程
掌握SQLite的EF Core集成、本地文件操作、数据备份/恢复、事务处理,让你快速实现桌面应用的本地数据存储,解决“数据存在哪里”的核心问题。
需求分析
设计一个本地待办事项管理工具,核心需求:
1.实体模型:待办项包含Id(主键)、Title(标题)、IsCompleted(完成状态)、CreateTime(创建时间);
2.CRUD操作:添加、查询(全部/按状态)、更新(完成状态)、删除待办项;
3.本地存储:数据库文件存放在用户目录(避免权限问题);
4.数据安全:支持手动备份/恢复数据库文件;
5.事务支持:批量添加待办项时用事务保证原子性;
6.跨平台兼容:同一代码可在Windows/macOS/Linux上运行。
代码实现
前置条件:
安装包:Microsoft.EntityFrameworkCore.Sqlite、Microsoft.Extensions.DependencyInjection;
目标框架:.NET 6+(跨平台支持)。

  1. 实体类定义
    csharp
	using System;
	using System.ComponentModel.DataAnnotations;
	using System.ComponentModel.DataAnnotations.Schema;
	
	/// <summary>
	/// 待办事项实体
	/// </summary>
	public class TodoItem {
	/// <summary>
	/// 主键:自增ID
	/// </summary>
	[Key]
	[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
	public int Id { get; set; }
	
	/// <summary>
	/// 待办标题:非空,最大长度100
	/// </summary>
	[Required]
	[MaxLength(100)]
	public string Title { get; set; } = string.Empty;
	
	/// <summary>
	/// 完成状态:默认未完成
	/// </summary>
	public bool IsCompleted { get; set; } = false;
	
	/// <summary>
	/// 创建时间:自动生成
	/// </summary>
	[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
	public DateTime CreateTime { get; set; }
	}
  1. DbContext配置(SQLite专属)
    csharp
	using Microsoft.EntityFrameworkCore;
	using System.IO;
	
	/// <summary>
	/// 待办事项数据库上下文
	/// </summary>
	public class TodoDbContext : DbContext {
	/// <summary>
	/// 数据库文件路径:用户目录下的todo.db(避免程序目录权限问题)
	/// </summary>
	private readonly string _dbPath = Path.Combine(
	Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), 
	"todo.db"
	);
	
	/// <summary>
	/// 待办项集合
	/// </summary>
	public DbSet<TodoItem> TodoItems { get; set; }
	
	/// <summary>
	/// 配置SQLite连接
	/// </summary>
	protected override void OnConfiguring(DbContextOptionsBuilder options) {
	// SQLite连接字符串:Data Source指定文件路径
	options.UseSqlite($"Data Source={_dbPath}")
	.LogTo(Console.WriteLine) // 输出SQL日志(调试用)
	.EnableSensitiveDataLogging(); // 显示敏感数据(调试用)
	}
	
	/// <summary>
	/// 实体映射配置(SQLite特有优化)
	/// </summary>
	protected override void OnModelCreating(ModelBuilder model) {
	model.Entity<TodoItem>(entity => {
	// SQLite自增主键配置(可选,EF Core自动适配,但明确指定更稳妥)
	entity.Property(e => e.Id)
	.ValueGeneratedOnAdd();
	
	// 创建时间默认值:SQLite的datetime('now')函数
	entity.Property(e => e.CreateTime)
	.HasDefaultValueSql("datetime('now')");
	
	// 索引:优化按完成状态查询
	entity.HasIndex(e => e.IsCompleted);
	});
	}
	}
  1. 待办事项服务类(CRUD+备份/恢复)
    csharp
	using System;
	using System.Collections.Generic;
	using System.Linq;
	using System.Threading.Tasks;
	using Microsoft.EntityFrameworkCore;
	using System.IO;
	
	/// <summary>
	/// 待办事项业务服务
	/// </summary>
	public class TodoService {
	private readonly TodoDbContext _dbContext;
	private readonly string _dbPath;
	private readonly string _backupPath;
	
	public TodoService(TodoDbContext dbContext) {
	_dbContext = dbContext;
	_dbPath = ((Microsoft.EntityFrameworkCore.Storage.RelationalConnection)_dbContext.Database.GetDbConnection()).ConnectionString.Split('=')[1];
	_backupPath = Path.ChangeExtension(_dbPath, ".backup.db");
	}
	
	/// <summary>
	/// 添加待办项
	/// </summary>
	public async Task AddTodoAsync(string title) {
	var todo = new TodoItem { Title = title };
	await _dbContext.TodoItems.AddAsync(todo);
	await _dbContext.SaveChangesAsync();
	Console.WriteLine($"✅ 添加待办:ID={todo.Id},标题={todo.Title}");
	}
	
	/// <summary>
	/// 批量添加待办项(事务保证原子性)
	/// </summary>
	public async Task BulkAddTodosAsync(List<string> titles) {
	using var transaction = await _dbContext.Database.BeginTransactionAsync();
	try {
	foreach (var title in titles) {
	await _dbContext.TodoItems.AddAsync(new TodoItem { Title = title });
	}
	await _dbContext.SaveChangesAsync();
	await transaction.CommitAsync();
	Console.WriteLine($"✅ 批量添加成功:共{titles.Count}条");
	} catch (Exception ex) {
	await transaction.RollbackAsync();
	Console.WriteLine($"❌ 批量添加失败:{ex.Message}");
	}
	}
	
	/// <summary>
	/// 查询所有待办项
	/// </summary>
	public async Task<List<TodoItem>> GetAllTodosAsync() {
	return await _dbContext.TodoItems.AsNoTracking().ToListAsync();
	}
	
	/// <summary>
	/// 更新待办项状态
	/// </summary>
	public async Task UpdateTodoStatusAsync(int id, bool isCompleted) {
	var todo = await _dbContext.TodoItems.FindAsync(id);
	if (todo == null) {
	Console.WriteLine($"❌ 待办项ID={id}不存在");
	return;
	}
	todo.IsCompleted = isCompleted;
	await _dbContext.SaveChangesAsync();
	Console.WriteLine($"✅ 更新待办:ID={id},状态={isCompleted}");
	}
	
	/// <summary>
	/// 删除待办项
	/// </summary>
	public async Task DeleteTodoAsync(int id) {
	var todo = await _dbContext.TodoItems.FindAsync(id);
	if (todo == null) {
	Console.WriteLine($"❌ 待办项ID={id}不存在");
	return;
	}
	_dbContext.TodoItems.Remove(todo);
	await _dbContext.SaveChangesAsync();
	Console.WriteLine($"✅ 删除待办:ID={id}");
	}
	
	/// <summary>
	/// 备份数据库
	/// </summary>
	public void BackupDatabase() {
	// 关闭当前DbContext连接(避免文件被占用)
	_dbContext.Database.CloseConnection();
	File.Copy(_dbPath, _backupPath, overwrite: true);
	_dbContext.Database.OpenConnection();
	Console.WriteLine($"✅ 备份成功:{_backupPath}");
	}
	
	/// <summary>
	/// 恢复数据库
	/// </summary>
	public void RestoreDatabase() {
	if (!File.Exists(_backupPath)) {
	Console.WriteLine($"❌ 备份文件不存在:{_backupPath}");
	return;
	}
	_dbContext.Database.CloseConnection();
	File.Copy(_backupPath, _dbPath, overwrite: true);
	_dbContext.Database.OpenConnection();
	Console.WriteLine($"✅ 恢复成功:{_dbPath}");
	}
	}
  1. 测试代码(桌面应用场景模拟)
    csharp
	using System;
	using System.Collections.Generic;
	using System.Threading.Tasks;
	using Microsoft.Extensions.DependencyInjection;
	
	class Program {
	static async Task Main() {
	// 依赖注入配置
	var services = new ServiceCollection()
	.AddDbContext<TodoDbContext>()
	.AddScoped<TodoService>()
	.BuildServiceProvider();
	
	var todoService = services.GetRequiredService<TodoService>();
	
	// 1. 添加单个待办
	await todoService.AddTodoAsync("学习SQLite");
	
	// 2. 批量添加待办
	await todoService.BulkAddTodosAsync(new List<string> { "写代码", "测试功能", "备份数据" });
	
	// 3. 查询所有待办
	var allTodos = await todoService.GetAllTodosAsync();
	Console.WriteLine(" 操作完成!");
}
}



  1. 实体类关键代码
  2. [Key] + [DatabaseGenerated(Identity)]:SQLite的自增主键需要此配置,确保Id自动生成且唯一; [Required] + [MaxLength]:约束Title非空且长度不超过100,避免无效数据; [DatabaseGenerated(Computed)]:标记CreateTime由数据库自动生成,配合后续的默认值配置。
  3. DbContext关键代码 UseSqlite连接字符串:Data Source=todo.db指定数据库文件路径,SQLite会自动创建该文件(如果不存在); HasDefaultValueSql("datetime('now')"):SQLite的日期函数,插入时自动填充当前时间; HasIndex(e => e.IsCompleted):为完成状态字段创建索引,加速按状态查询的效率。
  4. 服务类关键代码 BulkAddTodosAsync:使用事务保证批量添加的原子性,要么全部成功要么全部回滚; BackupDatabase:先关闭DbContext连接(避免文件锁定),再复制数据库文件到备份路径; RestoreDatabase:同理关闭连接,用备份文件替换原文件,实现数据恢复; AsNoTracking:查询时关闭跟踪,减少内存占用,提升只读场景性能。
  5. 测试代码关键逻辑 依赖注入:模拟桌面应用的依赖注入场景,解耦服务与DbContext; 批量添加:演示事务的使用,确保数据一致性; 备份/恢复:模拟用户手动操作,解决数据丢失问题。 基础知识拓展
  6. SQLite核心特性 文件型数据库:整个数据库存储在单个文件中,便于传输和备份; ACID兼容:支持原子性、一致性、隔离性、持久性,保证数据安全; 跨平台:支持Windows/macOS/Linux/Android/iOS,同一文件可在不同系统上使用; 轻量级:库文件仅几百KB,运行时无需安装服务; SQL支持:兼容大部分标准SQL语法,如SELECT/INSERT/UPDATE/DELETE、索引、事务等。
  7. 桌面应用最佳实践 数据库文件位置:存放在用户目录(如Environment.SpecialFolder.UserProfile),避免程序目录的权限问题; 备份策略:定期自动备份+手动备份,备份文件可压缩存储; 并发处理:SQLite默认是文件级锁,多线程写入时建议用单线程队列或异步锁; 性能优化: 为查询频繁的字段创建索引; 批量操作时用事务减少IO次数; 只读查询用AsNoTracking关闭跟踪; 安全防护:用参数化查询(EF Core自动支持)防止SQL注入,敏感数据加密存储。
  8. SQLite局限性 并发写入限制:单文件锁导致高并发写入性能下降,适合低并发场景; 大数据量处理:单个文件过大(如超过1GB)时,查询和备份速度变慢; 功能限制:不支持存储过程、触发器(部分支持)、外键约束(需手动开启)。 总结 SQLite是桌面应用本地存储的首选方案:轻量级、无依赖、跨平台、易备份。通过EF Core集成,你可以用熟悉的LINQ语法操作SQLite,无需编写复杂的SQL语句。本节的待办事项案例覆盖了CRUD、事务、备份/恢复等核心场景,完全满足桌面应用的日常需求。 关键Takeaway:桌面应用使用SQLite时,重点关注文件位置、备份策略、事务原子性和性能优化。掌握这些技巧,你可以快速构建稳定、可靠的本地数据存储功能。

本站原创,转载请注明出处:https://www.xin3721.com/ArticlecSharp/c49445.html



相关教程